[英]Setting Values on a derived class from the base class constructor using Reflection
我有两个这样的课程:
public abstract class MyBase
{
protected MyBase(){
Initialize();
}
protected IDictionary<string,string> _data;
private void Initialize() {
// Use Reflection to get all properties
// of the derived class (e.g., call new MyDerived() then
// I want to know the names "Hello" and "ID" here
var data = GetDataFromBackend(propertyNamesFromDerived);
_data = data;
}
}
public class MyConcrete : MyBase
{
public MyConcrete(){
// Possibly use Reflection here
Hello = _data["Hello"];
ID = new Guid(data["ID"]);
}
public string Hello {get;set;}
public Guid ID {get; set;}
}
如您所见,我希望我的基础 class 的构造函数了解我正在实例化的派生 class 的属性。
现在,这似乎是一个巨大的代码气味,所以让我提供更多关于我的意图的背景,也许有更好的方法。
我有一个存储键/值对的后端系统,本质上是一个Dictionary<string,string>
。 我想抽象出使用这个后端系统的方式,人们可以创建属性是后端系统的键的类。 当他们构建这个 object 时,它将自动从该系统加载数据并初始化所有变量。
换句话说,我刚刚重新发明了序列化,只是我不控制后端系统,只是让使用它变得非常轻松。 我不希望调用者在构建 object 后必须调用Initialize()
,因为在 100% 的情况下,您必须在构建后对其进行初始化。
我不想将初始化代码移动到派生类中,字符串到业务对象的转换除外。
我必须使用工厂吗? 或者在基本构造函数中查看派生 class 的属性名称是否安全? (不要关心它们的值并且它们没有被初始化,只需要名称)。
或者有没有更好的方法在字符串字典和具体业务 object 之间提供一个外观?
编辑:这是 .net 3.5,所以没有 System.Dynamic 这会使这变得微不足道:(
编辑 2:在查看了答案并进一步思考之后,我想我的问题现在真的可以归结为:是否从基本构造函数调用 GetType().GetProperties() 以获取属性名称以及它们是否都装饰有一定的属性保险箱?
等等,让我们在这里稍等片刻,并正确执行此操作。 这样做不应该是MyBase
的责任。
因此,您编写了一个 class 来为您管理从后端获取内容的方法,然后在该 class 上编写一个类似于
T Get<T>() where T : new()
你让Get
负责从后端读取字典并使用反射来填充T
的实例。 因此,你说
var concrete = foo.Get<MyConcrete>();
这并不难,而且是正确的方法。
顺便说一句, Get
的代码看起来像
T t = new T();
var properties = typeof(T).GetProperties();
foreach(var property in properties) {
property.SetValue(t, dictionary[property.Name], null);
}
return t;
其中dictionary
是您加载的键/值对。 事实证明有更优化的方法可以做到这一点,但除非它是一个瓶颈,否则我不会担心它。
更好的方法是让类直接使用字典:
public string Hello {
get { return (string)base.data["Hello"]; }
set { base.data["Hello"] = value; }
}
您可能希望在 getter 中调用TryGetValue
,以便在密钥不存在时返回默认值。 (您可能应该在基类的单独方法中执行此操作)
您可以制作代码片段以使属性更易于创建。
如果您不想这样做,可以调用GetType().GetProperties()
来获取 class 中属性的PropertyInfo
对象,然后调用SetValue(this, value)
。
这会很慢; 您可以使用各种技巧来使用表达式树、 CreateDelegate
或 IL 生成来加速它。
您是否考虑过使用ExpandoObject ? 有了它,您可以动态添加属性并检查它们(例如在序列化时)。
我不确定这是否是你真正应该做的,但这是你要求的(把它放在Initialize
中,你会得到一个派生属性名称的列表):
var derivedProps = this.GetType().GetProperties();
var propNames = new List<string>(derivedProps.Select(x => x.Name));
从那里,使用derivedProps
中的PropertyInfo
,您可以设置属性。
无论如何,您不能真正安全地对基类构造函数中的这些属性执行任何操作,因为某些派生构造函数可能会重置它们。 你最好进行两阶段加载(例如显式调用初始化)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.