通用方法,它采用实现另一个接口的接口,而不是调用正确的方法

问题描述:

我创建了一个自我搜索程序集,它具有可实现的ISearchable接口。它还提供了搜索电话号码的功能,因此它具有实现ISearchable的IPhoneNumberSearchable。然后我通过装配寻找实现IPhoneNumberSearchable的任何内容并调用Search。如果类实现了IPhoneNumberSearchable和ISearchable,它只会调用ISearchable方法。关于如何使这项工作的任何想法?代码跟随通用方法,它采用实现另一个接口的接口,而不是调用正确的方法

public class SearchManager 
{ 



    private ISearchItem[] Search<T>(string searchValue) where T: class,ISearchable 
    { 

     Assembly current = System.Reflection.Assembly.GetExecutingAssembly(); 

     IEnumerable<T> instances = from t in Assembly.GetExecutingAssembly().GetTypes() 
         where t.GetInterfaces().Contains(typeof(T)) 
           && t.GetConstructor(Type.EmptyTypes) != null 
         select Activator.CreateInstance(t) as T; 

     var list = new List<ISearchItem>(); 
     foreach (T item in instances) 
     { 
      try 
      { 
       T i = item as T; 
       list.AddRange(item.Search(searchValue)); 
      } 
      catch (System.Exception) { } 
     } 


     return list.ToArray(); 

    } 


    /// <summary> 
    /// Searches the specified search value. 
    /// </summary> 
    /// <param name="searchValue">The search value.</param> 
    /// <returns></returns> 
    public ISearchItem[] Search(string searchValue) 
    { 
     return Search<ISearchable>(searchValue); 
    } 


    /// <summary> 
    /// Searches for phone number. 
    /// </summary> 
    /// <param name="phoneNumber">The phone number.</param> 
    /// <returns></returns> 
    public ISearchItem[] SearchForPhoneNumber(string phoneNumber) 
    { 
     return Search<IPhoneSearchable>(phoneNumber); 
    } 

} 


/// <summary> 
/// 
/// </summary> 
public interface ISearchable 
{ 

    ISearchItem[] Search(string searchValue); 
} 

/// <summary> 
/// 
/// </summary> 
public interface ISearchable 
{ 

    ISearchItem[] Search(string searchValue); 
} 



public class CustomerManager : Search.IPhoneSearchable,Search.ISearchable 
{ 


    /// <summary> 
    /// Searches the specified phone number. 
    /// </summary> 
    /// <param name="phoneNumber">The phone number.</param> 
    /// <returns></returns> 
    Search.ISearchItem[] Search.IPhoneSearchable.Search(string phoneNumber) 
    { 
     //Search based upon phone number    
    } 

    /// <summary> 
    /// Searches the specified search value. 
    /// </summary> 
    /// <param name="searchValue">The search value.</param> 
    /// <returns></returns> 
    Search.ISearchItem[] Search.ISearchable.Search(string searchValue) 
    { 
     //Search on anything code 
    } 
} 
+0

我没有解决您的问题,但看看MEF - 它看起来像要重新发明*:http://mef.codeplex.com/ – BrokenGlass 2011-03-21 16:20:01

此代码不按预期工作,因为它工作正是根据语言规范。

基本上在你类CustomManager中你可以隐式地和明确地实现ISearchable。如果你想尝试调用此方法在常规码(不使用反射),它看起来像

CustomManager k = new CustomManager(); 
IPhoneSearchable x = k; 
x.Search("strings"); //calls IPhoneSearchable.Search() 
ISearchable y = k; 
y.Search("string"); //calls ISearchable.Search() 
k.Search("string); //calls ISearchable.Search()!!! 

的原因恰恰不是混淆编码器。您在类中实现接口,以便每次调用此方法都应调用此实现。如果由于某种其他原因您明确实现了另一个接口您需要指定您希望发生这种精确调用。

我不想介入你的设计,但对我来说这看起来有点奇怪。一种方法搜索某些东西,另一种搜索特定的东西,但两者具有相同的签名,同时提供稍微不同的功能。也许应该改变了IPhoneSearchable提供了一个名为

SearchPhones(string[] filters) 

方法实际调用从而隐藏从用户实现细节的方法搜索。通过提供Inteface IPhoneSearchable,您在合同规范中除了提供标记界面外什么也不做。

所以解决您的代码你或许应该创建实际MethodCalls的集合(因此CustomManager有两种方法调用,从ISearchable搜索和搜索IPhoneSearchable)

和迭代这个集合,并调用每个方法。

问候 卢克

+0

其实'K。搜索(“东西”)不存在:) – 2011-03-21 17:00:09

+0

对不起,AS CII的确我认为有隐式的方法实现。确实没有k.Search(“Something”) – luckyluke 2011-03-21 20:04:24

对于由幸运的路克你的代码解释的原因将无法正常工作。但是,而不是创建

实际MethodCalls(因此CustomManager有两种方法调用,从ISearchable搜索和IPhoneSearchable搜索),然后遍历这个集合,并调用每个方法

你可以集合做这样的事情(我已经略有改变您的代码):

public interface ISearch 
{ 
    IEnumerable<string> Search(string filter); 
} 

public interface IPhoneSearch : ISearch 
{ 
    new IEnumerable<string> Search(string filter); 
} 

public class Searchable : IPhoneSearch 
{ 
    public IEnumerable<string> Search(string filter) 
    { 
     yield return "Phone!"; 
    } 

    IEnumerable<string> ISearch.Search(string filter) 
    { 
     yield return "Normal!"; 
    } 
} 

然后在你的搜索:

static IEnumerable<string> Search<T>(string searchValue) where T : class, ISearch 
{ 
    var current = Assembly.GetExecutingAssembly(); 
    var instances = from t in Assembly.GetExecutingAssembly().GetTypes() 
        where !t.IsInterface 
        where typeof(T).IsAssignableFrom(t) 
        select (dynamic)Activator.CreateInstance(t); 

    foreach (var item in instances) 
    { 
     foreach (var occurrence in item.Search(searchValue)) 
     { 
      yield return occurrence; 
     } 
    } 
} 

无论如何,我会建议改变这个实现,就像luckyluke说的那样。

+0

你的观点是有效的ASCII,我们不知道的是,如果他只想打电话搜索或搜索或两者(因此我建议的方法呼叫收集)。并且+1使用IsAssignalbleFrom(这样一个清晰的事情,但略有不同的方法 - 但它可能是他有隐式转换.. – luckyluke 2011-03-21 20:06:32

+0

是的我想能够分开打电话给他们我也想定义一个或两个的能力。我的主要问题是即使泛型类型是IPhoneSearchable,当我调用搜索泛型类型(IPhoneSearchable)时,它仍然称为ISearchable方法。 – 2011-03-24 13:58:11

我的主要问题是即使泛型类型是IPhoneSearchable,当我调用搜索泛型类型(IPhoneSearchable)时,它仍然称为ISearchable方法。

我可以让它工作的唯一方法是通过反射使用以下代码来调用搜索。

 var list = new List<ISearchItem>(); 
     foreach (T item in instances) 
     { 


      try 
      { 

       var type = typeof(T); 

       var inter = item.GetType().GetInterface(type.Name); 

       var results = (ISearchItem[])inter.InvokeMember("Search", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, item, new object[] { searchValue }); 
       if(results != null) 
        list.AddRange(results); 
      } 
      catch (System.Exception) { } 
     }