在运行时修改类属性

时间:2011-01-27 12:48:21

标签: c# linq-to-sql reflection .net-3.5 attributes

我不确定我是否有可能看到:
Change Attribute's parameter at runtime.
我的情况非常相似,但我试图在运行时更改类的属性:

[Category("Change me")]
public class Classic
{
    public string Name { get; set; }
}

其中一个答案是:

Dim prop As PropertyDescriptor = TypeDescriptor
    .GetProperties(GetType(UserInfo))("Age")
Dim att As CategoryAttribute = DirectCast(
     prop.Attributes(GetType(CategoryAttribute)),
     CategoryAttribute)
Dim cat As FieldInfo = att.GetType.GetField(
     "categoryValue",
      BindingFlags.NonPublic Or BindingFlags.Instance)
cat.SetValue(att, "A better description")

更改为更易阅读的格式,感谢Marc Gravell:

TypeDescriptor.AddAttributes(table, new Category{ Name = "Changed" });

使用TypeDescriptor时,一切都很好,但使用时:

var attrs = (Category[])typeof(Classic).GetCustomAttributes(
    typeof(Category),
    true);
attrs[0].Name

名称包含“更改我”文字 有没有办法在运行时更改此属性?

修改
我在设计器中为Linq2Sql需要这个,生成的代码具有DB模式。我想使用用户的默认模式而不使用XML映射或更改生成的代码(表仍处于开发阶段并经常更改)。

设计师代码是:

[global::System.Data.Linq.Mapping.TableAttribute(Name="DbSchema.MyTable")]
public partial class MyTable

我希望该属性为:

[TableAttribute(Name="MyTable")] 

现在我已经深入研究了框架代码,我认为linq2sql使用:

TableAttribute[] attrs = (TableAttribute[])typeof(MyTable)
   .GetCustomAttributes(typeof(TableAttribute), true);

当我使用TypeDescriptor更改属性时,GetCustomAttributes中的值不会更改。

3 个答案:

答案 0 :(得分:2)

完全避免反射 ,您可以通过TypeDescriptor执行此操作:

using System;
using System.ComponentModel;
using System.Linq;
[Category("nice")]
class Foo {  }
static class Program
{
    static void Main()
    {
        var ca = TypeDescriptor.GetAttributes(typeof(Foo))
              .OfType<CategoryAttribute>().FirstOrDefault();
        Console.WriteLine(ca.Category); // <=== nice
        TypeDescriptor.AddAttributes(typeof(Foo),new CategoryAttribute("naughty"));
        ca = TypeDescriptor.GetAttributes(typeof(Foo))
              .OfType<CategoryAttribute>().FirstOrDefault();
        Console.WriteLine(ca.Category); // <=== naughty
    }
}

答案 1 :(得分:0)

如果您使用反射,那么不太喜欢这样 - 反射属性无法替换 - 只有组件模型视图是受TypeDescriptor影响。但是,您可以将CategoryAttribute子类化为您的目的。特别适用于i18n。

using System.ComponentModel;
using System;
[MyCategory("Fred")]
class Foo {  }
static class Program
{
    static void Main()
    {
        var ca = (CategoryAttribute)Attribute.GetCustomAttribute(typeof(Foo), typeof(CategoryAttribute));
        Console.WriteLine(ca.Category);
              // ^^^ writes "I was Fred, but not I'm EVIL Fred"
    }
}
class MyCategoryAttribute : CategoryAttribute
{
    public MyCategoryAttribute(string category) : base(category) { }
    protected override string GetLocalizedString(string value)
    {
        return "I was " + value + ", but not I'm EVIL " + value;
    }
}

答案 2 :(得分:0)

您需要对属性进行编码,以便它支持运行时值。例如,验证属性通过设置资源类型和资源字符串而不是静态消息字符串来支持消息的国际化。

另一种方法是使用IOC容器(如StructureMap或Unity)来提供一些提供值的对象/服务。

如果您不想将属性与特定容器耦合,请使用Patterns and Practices组提供的Common ServiceLocator包装。