在 C# 中,如何更改不可继承类中属性的默认值属性

本文关键字:属性 默认值 可继承 何更改 | 更新日期: 2023-09-27 18:33:21

这是我的情况:

有一个我成功继承的第三方组件控件,现在我正在对它进行一些处理。

该自定义的一部分是更改它拥有的某些属性的默认值。

到目前为止一切顺利,但是这个控件中有一些"子"类,我也想更改它们的属性默认值。

我所说的"子"类是指:假设我的控件称为 SomeControl,所以它有属性,但它也有一个可扩展的属性,比如:SomeControl.Rows,这。Rows 属性返回具有自己的属性的 RowCollection。所以这就是我所说的"子"类的意思(如果有更好的术语,请纠正我(

无论如何,如果我想更改 RowCollection 类中的一些默认值,我也需要继承它。问题是 RowCollection 的 Ctor 是内部的,所以我不能继承该类。

那么,我还有其他方法可以更改无法继承的类中属性的 DefaultValue 属性吗?

也许通过反思?

我需要为我现有的实例(对象(更改它 - 一个实例,而不是一般的班级..(因为在从中创建 1 个对象后,不会再创建更多对象。

谢谢

在 C# 中,如何更改不可继承类中属性的默认值属性

总结:我认为不可能通过反思来做到这一点,但这是我的做法:

首先获取所需的属性:

var defValAttr = typeof (SomeControl.RowCollection)
     .GetProperty("yourProperty")
     .GetCustomAttributes(typeof(DefaultValueAttribute), false)
     .First()
     as DefaultValueAttribute;

DefaultValueAttribute 有一个 .值属性,这是只读的。要修改它,您需要再次反射以更改私有 .value 字段:

var valueField= typeof (DefaultValueAttribute)
     .GetField("value", BindingFlags.NonPublic 
                      | BindingFlags.GetField 
                      | BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);

自己还没有测试过这个,但据我所知这是行不通的。GetCustomAttributes 返回的对象不是实际属性;您可以通过这种方式获取实际属性的值,但不能更改它们。(请参阅是否可以在 C# 中动态添加属性?

但是,即使这有效,它也会更改 SomeControl.Rows 的所有实例的默认值,无论它们是在自定义派生控件中还是在基控件中。无法仅更改单个实例的默认值,因为此值每个类仅存储一次,而不是每个实例存储一次。如果对象的每个实例都有每个属性的副本,那将是非常浪费的。

所以总而言之,我认为没有办法做到这一点。

作为替代方法,您可以反编译第三方程序集并使用 InternalsVisibleTo 添加您自己的程序集,这样您就可以访问内部构造函数。


附录:可能仍然有一种方法可以执行此操作,具体取决于您要更改的属性类型。通过反射访问的属性正如我所说,可能是不可改变的。但是,Visual Studio 编辑器和整个 WPF 组件模型实际上使用 TypeDescriptor 来管理语言中内置的基本属性系统之上的属性。您可能能够更改 TypeProvider 使用的属性,如果代码稍后通过 TypeScriptor 访问这些属性,它可能会看到更改的值。

以下内容再次未经测试:

var instanceOfRow = instanceOfYourControl.Rows;
var defValAttr = TypeDescriptor
     .GetProperties(instanceOfRow)["yourProperty"]
     .Attributes[typeof (DefaultValueAttribute)]
     as DefaultValueAttribute;
var valueField= typeof (DefaultValueAttribute)
     .GetField("value", BindingFlags.NonPublic 
                      | BindingFlags.GetField 
                      | BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);