构建一个实现接口中所有方法的类

时间:2014-02-05 18:54:30

标签: c# unit-testing casting polymorphism

如果一个类碰巧实现了接口中的所有方法(但没有明确地实现它),有没有办法将类的实例强制转换为该接口?

为了演示这个问题,我设置了以下简单类。 Scavenger是我要进行单元测试的演示class

IFinder interface可以由dictionary实现(或者可以通过其他方式实现)。 Finder是界面的示例实现,使用字典来处理提升。

//System under test
public class Scavenger
{
    private readonly IFinder _lookup;

    public Scavenger(IFinder lookup)
    {
        _lookup = lookup;
    }

    public string WhatIs(string key)
    {
        if (_lookup.ContainsKey(key)) return _lookup[key];
        return null;
    }
}

//Interface that can be met by a dictionary
public interface IFinder
{
    bool ContainsKey(string key);
    string this[string key] { get; set; }
}


//Implement IFinder using a dictionary
public class Finder : Dictionary<string,string>, IFinder
{
    public Finder()
    {
        this.Add("A","Hello");
        this.Add("B","Goodbye");
    }
}

我希望能够沿着这些路线为Scavenger设置测试...

    /// <summary>
    /// This will fail because due to failed cast a Dictionary to an IFinder
    /// </summary>
    [TestMethod]
    public void LookupUsingDictionary()
    {
        var dic = new Dictionary<string, string>();
        dic.Add("A","B");
        var scavenger = new Scavenger(dic as IFinder);
        var res = scavenger.WhatIs("A");
        Assert.AreEqual("B", res);
    }

问题在于(dic as IFinder) == null。我知道我可以设置一个类似于Finder的模拟类,或者使用模拟框架,但我只是想要检查我是否缺少某种方法来编写字典来完成这项工作

4 个答案:

答案 0 :(得分:3)

当您有一个接口和一个实现所有适当方法的类但没有实现该接口时,您可以使用适配器模式来实现您的目标。创建一个实现给定接口的类,并接受具有所有所需方法的类型的实例。然后,它可以将所有方法重定向到组合类:

public class DictionaryFinder : IFinder
{
    private Dictionary<string, string> dictionary;
    public DictionaryFinder(Dictionary<string, string> dictionary)
    {
        this.dictionary = dictionary;
    }


    public bool ContainsKey(string key)
    {
        return dictionary.ContainsKey(key);
    }

    public string this[string key]
    {
        get { return dictionary[key]; }
        set { dictionary[key] = value; }
    }
}

这允许你写:

var scavenger = new Scavenger(new DictionaryFinder(dic));

答案 1 :(得分:2)

不,你不能这样做。这称为duck typing和C#不允许这样做。

答案 2 :(得分:1)

您可以使用dynamic关键字来完成此操作......

像这样制作你的清道夫类:

public class Scavenger
{
    private readonly dynamic _lookup;

    public Scavenger(dynamic lookup)
    {
        _lookup = lookup;
    }

    public string WhatIs(string key)
    {
        if (_lookup.ContainsKey(key)) return _lookup[key];
        return null;
    }
}

这将尝试在运行时找到方法。有关详情,请参阅:http://msdn.microsoft.com/en-us/library/dd264741.aspx

答案 3 :(得分:1)

您可以使用ImpromptuInterface。我用它来实际上做类似鸭子的行为。

在某种程度上,由于4.0中引入的动态语言运行时(我相信它是4.0),C#确实允许鸭子打字,只是要非常小心你不要自己烧。 ImpromptuInterface证明了这一点。