2014-10-27 92 views
1

我有一个接受接口的方法的基类。我想在子类中找到与此接口最匹配的方法。例如:基于C#中基类动态参数调用的子类查找方法

abstract class Base<T> 
{ 
    public T Get(IParam parameter){ 
    return Provide(parameter as dynamic); 
    } 

    public abstract T Provide(IParam parameter); 
} 

class Impl<string> : Base<string> 
{ 
    public string Provide(IParam parameter) 
    { 
    return "default value"; 
    } 

    public string Provide(ParamImplementation1 parameter) 
    { 
    return "value for implementation 1"; 
    } 

    public string Provide(ParamImplementation2 parameter) 
    { 
    return "value for implementation 2"; 
    } 
} 

不幸的是,每次都会返回默认值。当实际实现在子类中时,似乎动态关键字不起作用。有什么办法让这个工作?

+2

动态关键字这里没有任何区别,抽象方法的实现必须完全有其相同的签名。这就是为什么每次只调用Provide(IParam参数),并且在这种情况下永远不会改变。 – 2014-10-27 14:58:01

+1

“ParamImplementation1”和“ParamImplementation1”的重载不是基本抽象类的一部分,所以当“Base”调用Provide时,它只会返回它知道的IParam版本。 – DavidG 2014-10-27 15:03:07

回答

1

为什么不检查Provide方法重写中的parameter的实际类型?

private abstract class Base<T> 
{ 
    public T Get(IParam parameter) 
    { 
     return Provide(parameter); 
    } 

    public abstract T Provide(IParam parameter); 
} 

private class Impl : Base<string> 
{ 
    public override string Provide(IParam parameter) 
    { 
     if (parameter is ParamImplementation1) 
      return "value for implementation 1"; 
     if (parameter is ParamImplementation2) 
      return "value for implementation 2"; 
     return "default value"; 
    } 
} 
+0

使方法具有通用性的要点是什么?没有这个,它的工作方式也是一样。 – DavidG 2014-10-27 15:12:26

+0

@DavidG我同意,没有必要仿制药,我的坏。 – Dmitry 2014-10-27 15:13:17

+0

我有很多不同的IParam实现,每个都有不同的属性。拥有许多ifs的巨大方法使其难以理解并且难以测试。 – Marius 2014-10-27 16:15:33

0

你可能只是一个创建单一的方法:

public override string Provide(IParam parameter) 
{ 
    return (Parameter is ParamImplementation1) ? "default value" : 
     (Paramater is ParamImplementation2) ? "value for implementation 1": 
     "default value"; 
} 
0

您可以处理在默认provide(IParam param)方法。

private readonly IDictionary<Type, MethodInfo> _methods; 

public Impl() { 
    var methods = this.GetType().GetMethods(
     BindingFlags.Public | 
     BindingFlags.NonPublic | 
     BindingFlags.Instance | 
     BindingFlags.FlattenHierarchy); 

    var provide = methods 
     .Where(m => m.Name.Equals("Provide", StringComparison.Ordinal) && m.GetParameters().Length == 1) 
     .ToList(); 

    _methods = when.ToDictionary(m => m.GetParameters().First().ParameterType, m => m); 
} 

public string Provide(IParam param) { 
    MethodInfo methodInfo; 
    if (dictionary.TryGetValue(param.GetType(), out methodInfo)) { 
     return methodInfo.Invoke(this, new object[] { param }); 
    } 

    return "default value"; 
} 

所以,你检查你的类名为Provide方法并将其保存在一本字典。出于性能原因,我会将此字典存储在类成员中。然后你可以问字典是否有你的特定参数类型的方法。

使用这种技术,您不必在添加新的Provide()实施时更改其他方法或切换/案例语句。

1

因此解决的办法似乎是投thisdynamic,像这样:

abstract class Base<T> 
{ 
    public T Get(IParam parameter){ 
    return (this as dynamic).Provide(parameter as dynamic); 
    } 

    public abstract T Provide(IParam parameter); 
} 

class Impl<string> : Base<string> 
{ 
    public string Provide(IParam parameter) 
    { 
    return "default value"; 
    } 

    public string Provide(ParamImplementation1 parameter) 
    { 
    return "value for implementation 1"; 
    } 

    public string Provide(ParamImplementation2 parameter) 
    { 
    return "value for implementation 2"; 
    } 
} 
+0

'动态'已知在内部使用反射。正如我所说,反射是我看到的唯一选择。你找到了最紧凑的方式。很棒的工作! +1 – Dmitry 2014-10-27 18:46:29