在运行时更改属性的参数
时间:2020-03-05 18:49:51 来源:igfitidea点击:
我不确定是否可以在运行时更改属性的参数?例如,在装配体内,我有以下课程
public class UserInfo { [Category("change me!")] public int Age { get; set; } [Category("change me!")] public string Name { get; set; } }
这是由第三方供应商提供的类,我无法更改代码。但是现在我发现上面的描述是不正确的,并且当我将上述类的实例绑定到属性网格时,我想将"更改我"类别名称更改为其他名称。
我可以知道该怎么做吗?
解决方案
回答
我真的不这么认为,除非有一些时髦的反射可以将其拉开。属性装饰是在编译时设置的,据我所知是固定的
回答
好吧,你每天都学到新东西,显然我撒谎:
What isn’t generally realised is that you can change attribute instance values fairly easily at runtime. The reason is, of course, that the instances of the attribute classes that are created are perfectly normal objects and can be used without restriction. For example, we can get the object: ASCII[] attrs1=(ASCII[]) typeof(MyClass).GetCustomAttributes(typeof(ASCII), false); …change the value of its public variable and show that it has changed: attrs1[0].MyData="A New String"; MessageBox.Show(attrs1[0].MyData); …and finally create another instance and show that its value is unchanged: ASCII[] attrs3=(ASCII[]) typeof(MyClass).GetCustomAttributes(typeof(ASCII), false); MessageBox.Show(attrs3[0].MyData);
http://www.vsj.co.uk/articles/display.asp?id=713
回答
我们解决问题了吗?
这是实现可接受解决方案的可能步骤。
- 尝试创建一个子类,重新定义更改" [Category]"属性所需的所有属性(将其标记为" new")。例子:
public class UserInfo { [Category("Must change")] public string Name { get; set; } } public class NewUserInfo : UserInfo { public NewUserInfo(UserInfo user) { // transfer all the properties from user to current object } [Category("Changed")] public new string Name { get {return base.Name; } set { base.Name = value; } } public static NewUserInfo GetNewUser(UserInfo user) { return NewUserInfo(user); } } void YourProgram() { UserInfo user = new UserInfo(); ... // Bind propertygrid to object grid.DataObject = NewUserInfo.GetNewUser(user); ... }
以后编辑:如果我们有大量属性可能需要重写属性,则该解决方案的这一部分将无法使用。这是第二部分的地方:
- 当然,如果类不是可继承的,或者我们有很多对象(和属性),这将无济于事。我们将需要创建一个全自动代理类,该类将获取类并创建一个动态类,应用属性,并且当然在这两个类之间建立连接。只需使用反射,我们就可以走上正确的道路。
回答
同时,从下面的文章中我得出了部分解决方案:
- ICustomTypeDescriptor,第1部分
- ICustomTypeDescriptor,第2部分
- 在运行时向(或者从)PropertyGrid添加(删除)项
基本上,我们将创建一个通用类" CustomTypeDescriptorWithResources <T>",该类将通过反射获取属性,并从文件中加载" Description"和" Category"。 .resx
))
回答
我们可以很容易地将大多数通用属性子类化以提供这种可扩展性:
using System; using System.ComponentModel; using System.Windows.Forms; class MyCategoryAttribute : CategoryAttribute { public MyCategoryAttribute(string categoryKey) : base(categoryKey) { } protected override string GetLocalizedString(string value) { return "Whad'ya know? " + value; } } class Person { [MyCategory("Personal"), DisplayName("Date of Birth")] public DateTime DateOfBirth { get; set; } } static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.Run(new Form { Controls = { new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = new Person { DateOfBirth = DateTime.Today} }}}); } }
还有更多复杂的选项,涉及编写自定义的" PropertyDescriptor",通过" TypeConverter"," ICustomTypeDescriptor"或者" TypeDescriptionProvider"公开,但这通常是多余的。
回答
万一其他人走上这条路,答案是我们可以通过反思来做到,除非我们不能这样做,因为框架中存在错误。这是处理方式:
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")
一切都很好,只不过类别属性对所有属性都进行了更改,而不仅仅是"年龄"。