Атрибут C # со сложной структурой - PullRequest
3 голосов
/ 20 апреля 2011

РЕДАКТИРОВАТЬ: похоже, невозможно иметь только один атрибут со всем внутри, как решение № 2, поэтому я в конечном итоге использовал решение № 3, которое не подвержено ошибкам в отличие от решения № 1.

У меня есть следующий атрибут:

// Solution #1 (working)
[Module(Name="Module1", Guid="xxxxx",
  NeededFiles_Name = new string[]
  {
    "module1Conf.xml",
    "module1.sql",
    "resourcesWindows",
    "resourcesUnix",
  },
  NeededFiles_OS = new OSType[]
  {
    All,
    All,
    Windows,
    Unix,
  }
  NeededFiles_Component = new ComponentType[]
  {
    Server,
    Server,
    All,
    All
  }
)]

Проблема в том, что заполнить свойства NeededFile_Xxx нелегко. Было бы проще иметь только одно свойство типа

// Solution #2 (NOT working)
[Module(Name="Module1", Guid="xxxxx",
  NeededFile = new FileInfo[]
  {
    new FileInfo("module1Conf.xml", All, Server),
    ...
  }
)]

но это не разрешено компилятором ( NeededFile не является допустимым аргументом именованного атрибута, поскольку он не является допустимым типом параметра атрибута .

Я мог бы также разделить свой атрибут на несколько и сделать

// Solution #3 (working)
[Module(Name="Module1", Guid="xxxxx"]
[NeededFile("module1Conf.xml", All, Server)]
[NeededFile("module1.sql", All, Server)]
[NeededFile(...)]

но я бы предпочел оставить все как есть.

Возможно ли это сделать? Есть ли лучший способ сделать это?

1 Ответ

7 голосов
/ 20 апреля 2011

Почему это (второй вариант) не разрешено?Я просто попробовал следующее:

public class MyFileInfo
{
    public MyFileInfo(string fname, string somethingElse, string anotherThing);
}

public class ModuleAttribute : System.Attribute
{
    public ModuleAttribute(string Name, string Guid, params MyFileInfo[] myFileInfoList)
    {
    }
}

[Module("Module1", "xxxx",
    new MyFileInfo("a", "b", "c"),
    new MyFileInfo("a", "d", "f"))
]
public class TestClass
{
}

И компилятор не жаловался.Я думаю, что вы можете достичь в значительной степени именно того, что вы пытаетесь сделать.

Редактировать: это то, что я получаю за то, что позволил intellisense делать мою компиляцию для меня посреди ночи после пары пива.Как вы (и я) обнаружили, что аргументы Attribute должны быть константами или списками констант - ограничение, которое явно исключает классы и структуры.

Я думаю, лучшее, что вы собираетесь сделать, это передатьв сериализованной версии данных вы пытаетесь пометить атрибут.Затем конструктор атрибута может выполнить фактическую инициализацию объекта во время выполнения.Это теряет проверку во время компиляции ваших инициализаторов, но приближает вас к компактности кода, который вы искали.

public class MyFileInfo
{
    string fname;
    string anotherThing;
    string somethingElse;
    public MyFileInfo(string serializedFileInfo)
    {
        string[] parts = serializedFileInfo.Split(',');
        fname = parts[0];
        anotherThing = parts[1];
        somethingElse = parts[2];
    }
    public static implicit operator MyFileInfo(string things)
    {
        return new MyFileInfo(things);
    }
}

public class ModuleAttribute : System.Attribute
{
    List<MyFileInfo> fiList;
    public ModuleAttribute(string Name, string Guid, params string[] serializedFileInfoList)
    {
        fiList = serializedFileInfoList.Select(s => new MyFileInfo(s)).ToList();
    }
}

[Module("Module1", "xxxx",
    "a,b,c",
    "d,e,f"
    )
]
public class TestClass
{
}

Действительно, я думаю, что вы должны просто обработать его через отдельный атрибут длякаждый файл.

...