如何在C#中定义接口的默认实现?

31

在C#中有一些黑魔法代码,可以定义接口的默认实现。

因此,你可以这样编写:

var instance = new ISomeInterface();
任何建议吗?
更新1:请注意,我没有问这是否是一个好主意。只是如何做到这一点。
更新2:对于看到已接受答案的任何人。
- Marc Gravel 在"Newing up" Interfaces中说:“这只应被视为一种好奇心。” - Eric Lippert 在"Newing up" Interfaces中说:“使用为COM互操作设计的工具来完成完全不同的任务是一个坏主意。这会使下一个负责维护代码的人无法理解您的代码。” - Stephen Cleary 在下面的评论中说:“虽然它可能有效,但如果有理性的程序员在生产代码中找到了它,他将重构为使用基类或依赖注入。”

一些关于此的文章:https://dev59.com/SXNA5IYBdhLWcg3wGJwV 和 http://blogs.msdn.com/b/ericlippert/archive/2007/04/20/chained-user-defined-explicit-conversions-in-c-part-three.aspx - Eric Lippert
还没有明智的方法来做这件事吗? - William Jockusch
@WilliamJockusch仍然是我所知道的唯一一个。 - Simon
3个回答

34

下面就是黑科技的精髓:

class Program
{
    static void Main()
    {
        IFoo foo = new IFoo("black magic");
        foo.Bar();
    }
}

[ComImport]
[Guid("C8AEBD72-8CAF-43B0-8507-FAB55C937E8A")]
[CoClass(typeof(FooImpl))]
public interface IFoo
{
    void Bar();
}

public class FooImpl : IFoo
{
    private readonly string _text;
    public FooImpl(string text)
    {
        _text = text;
    }

    public void Bar()
    {
        Console.WriteLine(_text);
    }
}

请注意,你不仅可以实例化一个接口,而且还可以向其构造函数传递参数 :-)


1
而且有了关键字“CoClass”,谷歌之神再次与我同在。 http://ayende.com/Blog/archive/2009/08/15/instantiating-interfaces.aspx http://marcgravell.blogspot.com/2009/08/who-says-you-cant-instantiate-interface.html - Simon
@Simon,这是我推荐你调整RSS阅读器的两个博客 :-) - Darin Dimitrov
@Daren已经拥有它们了。但是我所有的“接口默认实现”的组合都没有结果。信噪比不好 :) - Simon
1
@daren 有点有趣,你发了回答之后那些说“不可能”的答案却得到了赞同。 - Simon
如果我在同事的代码中看到这个,我会开除他们。 - jbrown

3

1
我给所有不正确的答案点了踩,因为它们是错误的。没有理性可言。参见Darin的答案。 - Simon
2
我看到了“正确”的答案。虽然它可能有效,但如果有理性的编码人员在生产代码中发现它,他们会重构为使用基类或依赖注入。 - Stephen Cleary
@Setphen 同意。我编辑了问题,希望没有人认为这是个好主意。 - Simon

1

也许你指的是依赖注入?当使用 DI 框架(例如 Ninject 或 Unity)时,你可以为每个接口定义默认实例,然后像这样使用它:

(假设你有 IWeapon 接口和 Sword 实现它)

IKernel kernel = new StandardKernel();
kernel.Bind<IWeapon>().To<Sword>();
var weapon = kernel.Get<IWeapon>();

但是Ninject(以及大多数其他IoC框架)可以做一些更聪明的事情,比如说我们有一个类Warrior,它在构造函数中接受IWeapon作为参数。我们可以从Ninject获取Warrior的实例:
var warrior = kernel.Get<Warrior>();

Ninject将会把我们指定的IWeapon实现传递给Warrior构造方法,并返回新的实例。

除此之外,我不知道还有哪些语言特性能够支持这种行为。


好的建议,但不是我要找的。请参考Darin的回答。 - Simon
1
是的,我错过了你在问题中提到“黑魔法”的部分 :-)感谢你的提问 - 我学到了新东西! - arikfr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接