C# 结构复杂的属性

发布于 2024-11-02 06:44:10 字数 1068 浏览 3 评论 0原文

编辑:看起来不可能像解决方案 #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(...)]

但我宁愿将所有内容保持不变,

是否有更好的方法可以做到这一点?

EDIT: looks like it's not possible to have only one attribute with everything inside like solution #2, so I ended up using solution #3 which is not error prone unlike solution #1.

I have an attribute as follow:

// 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
  }
)]

The problem is that it's not easy to fill the NeededFile_Xxx properties. It would be easier to have only one property like

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

but it's not allowed by the compiler (NeededFile is not a valid named attribute argument because it is not a valid attribute parameter type.

I could also divide my attribute into severals and do

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

but I'd rather keep everything in the same.

Is it possible to do it? Is there a better way to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜警司 2024-11-09 06:44:10

为什么不允许(你的第二个选择)?我刚刚尝试了以下操作:

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
{
}

编译器没有抱怨。我认为你几乎可以实现你想要做的事情。

编辑:这就是我在半夜喝了几杯啤酒后让智能感知为我进行编译所得到的结果。正如您(和我)所发现的,属性参数必须是常量或常量列表 - 这是显式排除类和结构的限制。

我认为您能做的最好的事情就是传递您尝试标记到属性上的数据的序列化版本。然后属性构造函数可以在运行时进行实际的对象初始化。这会丢失初始化程序的编译时检查,但会让您更接近您正在寻找的代码的紧凑性。

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
{
}

实际上,我认为您应该通过每个文件的单独属性来处理它。

Why isn't it (you second option) allowed? I just tried the following:

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
{
}

And the compiler didn't complain. I think you can achieve pretty much exactly what you're trying to do.

Edit: that's what I get for letting intellisense do my compiling for me in the middle of the night after a couple beers. As you (and I) have discovered, Attribute arguments must be constants, or lists of constants - a restriction that explicitly excludes classes and structs.

I think the best you're going to be able to do is pass in a serialized version of the data you're trying to tag onto the attribute. Then the attribute constructor can do the actual object initialization at runtime. This loses compile-time checking of your initializers, but gets you a bit closer to the compactness of code you were looking for.

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
{
}

Really though, I think you should just handle it through a separate attribute for each file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文