如何推断基类中派生类的类型?

enz*_*nzi 5 c# generics type-inference

我想创建一个方法,允许我更改从我的基类派生的类的任意属性,结果应如下所示:SetPropertyValue("size.height", 50);- where size是我的派生类height的属性,是一个属性size.

我差不多完成了我的实现,但是在继续之前我想要解决的最后一个障碍,为了描述这个,我首先要解释一下我的实现:

  • 可以修改的属性使用属性进行修饰
  • 我的基类中有一个方法可以搜索所有派生类及其修饰属性
  • 对于每个属性,我生成一个"属性修饰符",一个包含2个委托的类:一个用于设置,另一个用于获取属性的值.
  • 属性修饰符存储在字典中,属性的名称为键
  • 在我的基类中,有另一个包含所有property-modifier-dictionaries的字典,其中相应类的Type作为键.

SetPropertyValue方法的作用是:

  • 使用派生类的具体类型获取正确的property-modifier-dictionary(< - 尚未解决)
  • 获取要更改的属性的属性修饰符(例如属性size)
  • 使用get或set委托修改属性的值

一些示例代码进一步澄清:

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 存储为对象,因为我找不到其他方法(不同的泛型类型参数) - 也许这也可以改进.
  • 我不能像Mehrdad建议的那样使用奇怪的重复模板模式.由于其他原因,我的基类不能通用(与手头的问题无关).

澄清什么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>>.

wrm*_*msr 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 { }
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 的部分,但我认为您已经完成了所有这些工作。