我想创建一个方法,允许我更改从我的基类派生的类的任意属性,结果应如下所示:SetPropertyValue("size.height", 50);
- 其中size
是我派生的属性class height
是size
的属性。
我差不多完成了我的实现,但是在继续之前还有一个我想要解决的最后一个障碍,为了描述这个我首先要解释一下我的实现:
SetPropertyValue
方法的作用是:
size
)进一步澄清的一些示例代码:
private static Dictionary<RuntimeTypeHandle, object> EditableTypes; //property-modifier-dictionary
protected void SetPropertyValue<T>(EditablePropertyMap<T> map, string property, object value) {
var property = map[property]; // get the property modifier
property.Set((T)this, value); // use the set delegate (encapsulated in a method)
}
在上面的代码中,T
是实际(派生)类的类型。我需要这种类型的get / set委托。问题是当我不知道T是什么时如何获得EditablePropertyMap<T>
。
我当前(丑陋)的解决方案是在派生类的覆盖虚拟方法中传递地图:
public override void SetPropertyValue(string property, object value) {
base.SetPropertyValue((EditablePropertyMap<ExampleType>)EditableTypes[typeof(ExampleType)], property, value);
}
这样做是:使用类的类型获取包含此类的属性修饰符的正确字典,将其强制转换为适当类型并将其传递给SetPropertyValue
方法。
我想摆脱派生类中的SetPropertyValue
方法(因为有很多派生类),但还不知道如何实现它。我不能只创建一个虚拟GetEditablePropertyMap<T>
方法,因为我无法推断T的具体类型。我也无法直接使用类型访问我的字典并从中检索EditablePropertyMap<T>
因为我无法从基类中的object
转换为它,因为我再次不知道T
。< / p>
我发现了一些推理类型的巧妙技巧(例如通过添加虚拟T
参数),但不能将它们应用于我的特定问题。我非常感谢您对我提出的任何建议。
编辑: 虽然这已经是一面文字了,但我还要补充一些注意事项:
EditablePropertyMap
存储为对象,因为我找不到其他方式(不同的泛型类型参数) - 也许这也可以改进。澄清EditableProperty
/ EditablePropertyMap
的作用:
public class EditableProperty<T> {
private Func<T, object> getter;
private Action<T, object> setter;
...
public object Get(T obj) { return getter(obj); }
public void Set(T obj, object value) { setter(obj, value);}
地图仅仅是Dictionary<string, EditableProperty<T>>
的包装。
答案 0 :(得分:1)
我不确定你是否愿意改变设计,但我认为curiously recurring template pattern可能就是你所需要的:
class Super<TDerived> where TDerived : Super<TDerived>
{
//Now we have access to TDerived here
}
class Derived : Super<Derived> { ... }
你也可以试着说:
typeof(MyClass).GetMethod("SetPropertyValue")
.MakeGenericMethod(new Type[] { derivedType })
.Invoke(dictionary, object[] { map, property, value });
但这会非常慢。
如果在编译时不知道类型,就无法快速完成此操作,因为根据定义,您必须在编译时绑定方法以避免运行时命中。
答案 1 :(得分:1)
http://msdn.microsoft.com/en-us/library/system.object.gettype.aspx - 有一个由Type键入的EditablePropertyMaps地图,在SetPropertyValue中通过GetType()获取派生类型的地图。我错过了什么吗?
此外:
public abstract class EditablePropertyMap { }
public class EditablePropertyMap<T> : EditablePropertyMap { }
编辑:我想我很难建议放弃泛型并传递对象,但现在我看到你想让代表保持通用。下面怎么样 - 我重新安排了一些东西,但它没有改变主旨:
abstract class EditableProperty { }
class EditableProperty<T> : EditableProperty {
public void Set(T obj, object value) { Console.WriteLine(value); }
}
abstract class EditablePropertyMap {
private static Dictionary<Type, EditablePropertyMap> maps = new Dictionary<Type, EditablePropertyMap>();
abstract public void AddProperty(string name, EditableProperty property);
abstract public void SetPropertyValue(object obj, string name, object value);
static public EditablePropertyMap Get(Type t) {
EditablePropertyMap map;
if(!maps.TryGetValue(t, out map)) {
map = (EditablePropertyMap)Activator.CreateInstance(
typeof(EditablePropertyMap<>)
.MakeGenericType(t));
maps.Add(t, map);
}
return map;
}
}
class EditablePropertyMap<T> : EditablePropertyMap {
private Dictionary<string, EditableProperty<T>> properties = new Dictionary<string, EditableProperty<T>>();
public override void AddProperty(string name, EditableProperty property) {
properties.Add(name, (EditableProperty<T>)property);
}
public override void SetPropertyValue(object obj, string name, object value) {
EditableProperty<T> property = properties[name];
property.Set((T)obj, value);
}
}
class DynamicObjectBase {
public void SetPropertyValue(string name, object value) {
EditablePropertyMap map = EditablePropertyMap.Get(GetType());
map.SetPropertyValue(this, name, value);
}
}
class SomeDynamicObject : DynamicObjectBase {
}
class Program {
static void Main(string[] args) {
EditablePropertyMap map = EditablePropertyMap.Get(typeof(SomeDynamicObject));
map.AddProperty("wut", new EditableProperty<SomeDynamicObject>());
SomeDynamicObject o = new SomeDynamicObject();
o.SetPropertyValue("wut", 1);
}
}
我也没有做过在init上只使用类型创建EditableProperties的部分,但我认为你已经完成了所有这些。
答案 2 :(得分:0)
由于您无论如何都是从基类转换到派生类(在SetPropertyValue
中),为什么不将转换放在生成的修饰符委托中?然后SetPropertyValue
不再需要通用。
作为旁注,我知道你说性能很关键,但你有没有使用例如缓存PropertyInfo
个实例进行获取和设置?