2014-10-27 37 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