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

时间:2011-03-21 16:11:23

标签: c# interface

我正在创建一个自我搜索程序集,它具有可以实现的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
    }
}

3 个答案:

答案 0 :(得分:1)

此代码无法正常工作,因为它可以根据语言规范精确工作。

基本上在您的类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搜索)

并迭代此集合并调用每个方法。

问候 路加

答案 1 :(得分:0)

由于luckyluke解释的原因,您的代码将无效。但是,而不是创建

  

实际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所说。

答案 2 :(得分:0)

我的主要问题是即使泛型类型是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) { }
        }