enz*_*nzi 5 c# generics type-inference
我想创建一个方法,允许我更改从我的基类派生的类的任意属性,结果应如下所示:SetPropertyValue("size.height", 50);- where size是我的派生类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)
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,T是实际(派生)类的类型.我需要这种类型的get/set委托.问题是如何在EditablePropertyMap<T>不知道T是什么时获得.
我当前(丑陋)的解决方案是在派生类中的覆盖虚方法中传递映射:
public override void SetPropertyValue(string property, object value) {
base.SetPropertyValue((EditablePropertyMap<ExampleType>)EditableTypes[typeof(ExampleType)], property, value);
}
Run Code Online (Sandbox Code Playgroud)
这样做是:使用类的类型获取包含此类的属性修饰符的正确字典,将其强制转换为适当类型并将其传递给SetPropertyValue方法.
我想摆脱SetPropertyValue派生类中的方法(因为有很多派生类),但还不知道如何实现它.我不能只创建一个虚GetEditablePropertyMap<T>方法,因为我无法推断T的具体类型.我也无法直接使用类型访问我的字典并EditablePropertyMap<T>从中检索,因为我无法从object基类中转换它,因为我再也不知道T.
我发现了一些简洁的技巧来推断类型(例如通过添加一个伪T参数),但不能将它们应用于我的特定问题.我非常感谢您对我提出的任何建议.
编辑:虽然这已经是一面文字,但我还要补充一些注意事项:
EditablePropertyMaps 存储为对象,因为我找不到其他方法(不同的泛型类型参数) - 也许这也可以改进.澄清什么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);}
Run Code Online (Sandbox Code Playgroud)
地图只是一个包装纸Dictionary<string, EditableProperty<T>>.
http://msdn.microsoft.com/en-us/library/system.object.gettype.aspx - 拥有按 Type 键控的 EditablePropertyMaps 映射,在 SetPropertyValue 中通过 GetType() 获取派生类型的映射。我错过了什么吗?
此外:
public abstract class EditablePropertyMap { }
public class EditablePropertyMap<T> : EditablePropertyMap { }
Run Code Online (Sandbox Code Playgroud)
编辑:我想我不太建议放弃泛型并仅传递对象,但现在我看到您希望保持委托的泛型。下面怎么样 - 我重新安排了一些内容,但它并没有改变要点:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我也没有完成在 init 时仅从类型创建 EditableProperties 的部分,但我认为您已经完成了所有这些工作。