可以将接口添加到现有的.NET类型中吗?

时间:2011-08-03 17:39:48

标签: c# type-conversion

下面的示例涉及2个.NET类,它们都包含CommonMethod方法。我想设计MyMethod,可以接受任何类(使用),同时保留NetClassA和NetClassB常用的功能。 Case1会做到这一点,只有它是非法的,如下所述。 Case2也将完成目标,除了INetClassA和INetClassB不存在。因此,我的问题是有一种方法可以在现有的.NET类型(案例3)上强制使用自定义接口(ICommonNetMethods)吗?我的问题的替代解决方案受到欢迎。

// Case 1:  Illegal because "where" can only have 1 base class
public void MyMethod<Ttype>(Ttype myClass) where Ttype : NetClassA, NetClassB {}

// Case 2:  Legal to utlize multiple "where" interface types
public void MyMethod<Ttype>(Ttype myClass) where Ttype : INetClassA, INetClassB {}

// Case 3:  For this to work ICommonNetMethods must be added to NetClassA/NetClassB
public void MyMethod<Ttype>(Ttype myClass) where Ttype : ICommonNetMethods {}

NetClassA() { This .NET class has method CommonMethod() }
NetClassB() { This .NET class has method CommonMethod() }

interface ICommonNetMethods { void CommonMethod() }

谢谢, aidesigner

6 个答案:

答案 0 :(得分:13)

有很多方法可以解决这个问题,包括创造性思维。

最明显的是:

Adapter Pattern

构建您的界面,然后是两个适配器,每个适配器都采用NetClassA和其他NetClassB。您的公共代码保持不变,特定的生命在适配器中。

这适用于密封课程。你没有从NetClassA或NetClassB开始。我想把这个留给你来弄清楚实现,如果你想要代码实现我会在一天之内回来发布它。

其他要注意的事项:

Extension Methods

和/或

Reflection

更多帮助

             =====================
             = ICommonNetMethods =
             =====================
                       | (derive)
         |-------------------------------|
====================            ====================
= NetClassAAdapter =            = NetClassBAdapter =
====================            ====================
         | uses (not derive)             | uses (not derive)
   =============                   =============
   = NetClassA =                   = NetClassB =
   =============                   =============

答案 1 :(得分:8)

使用Func<>

假设有两个类A和B,每个类都有一个函数Foo(虽然这不是这个解决方案的真正要求,但是观察下面的C类):

public class A { int Foo() { return 1; } }
public class B { int Foo() { return 2; } }
public class C { int Deviant() { return 3; } }

然后在一些代码片段中,您将写:

var a = new A();
var b = new B();
var c = new C();
var fs = new Func<int>[] {() => a.Foo(), () => b.Foo(), () => c.Deviant()};

所以要使用它:

foreach(var func in fs) 
   Console.WriteLine(func());

反过来会输出:

1
2
3

Lambda函数在C#中是一个大问题,也是一门很好的学习技术。如果您不熟悉,并想了解更多信息,请从Microsoft's help页面开始。

如果您正在查看更大的接口,请考虑,如上所述,适配器模式。如果用你自己的具体适配器类包装你的每个对象的想法似乎太臃肿了,那么再次,Func&lt;&gt;救援。

public interface ISomeInterface
{
   void f1();
   int f2(string p1);
   ...
}

public class FuncImplementation : ISomeInterface
{
   public Action Func_f1 { get; set; }
   public Func<string,int> Func_f2 { get; set; }
   ...
   void f1() { Func_f1(); }
   int f2(string p1) { return Func_f2(p1); }
   ...
}

现在您可以内联新的Adapters:

var adaptA = new FuncImplementation { Func_f1 = MyF1, Func_f2 = Myf2 };
adaptA.f1();

答案 2 :(得分:4)

你不能在现有代码上强加一个接口(除非你使用像PostSharp这样的代码编织器,但那是作弊; - )。

相反,请考虑以下选项:

  1. 如果您的界面上只有一个方法,则可以使用 代替代表。
  2. 您可以为每个类型创建一个简单的包装类,并在那里实现接口。

答案 3 :(得分:3)

我能想到的唯一方法(从头到尾)是从有问题的.NET类派生出来并将接口添加到该实现中。但是,我认为这不是最佳解决方案。

为什么不简单地检查Ttype在方法中的类型,并根据类型执行相应的代码?

例如:

public void MyMethod<Ttype>(Ttype myClass)
{

    string className = typeof(Ttype).Name;

    switch (className)
    {
        case "NetClassA":
            // Do stuff
            break;
        case "NetClassB":
            // Do stuff
            break;
        default:
            // Do something if necessary
            break;
     }
}

答案 4 :(得分:1)

感谢所有人,我对各种选项印象深刻。首先,我已经开始寻求委托选项(The use of nested type parameters and recursion (C#))并且有一个几乎理想的解决方案。这个帖子的第二篇文章显示了我的确切实现。这种方法试图通过传递NETClassA(SrgsItem)和NetClassB(SrgsElement)所需的函数“Add”而不是整个类来解决问题。这几乎是完美的,除了C#缺乏“Generics Variance”支持正在阻碍。

至于其他选项,他们都非常有见地。在追求委托线程之后,我将尝试Michael和Andrew提出的Adapter / Func方法(将添加评论)。如果您有时间,请按照上面的委托主题进行操作,这可能有助于理解C#的另一个方面。

答案 5 :(得分:1)

C#4.0引入了dynamic关键字,允许C#开发人员使用duck typingadapter pattern的替代品)。有了它,您可以像这样定义MyMethod

public void MyMethod(dynamic myClass)
{
    myClass.CommonMethod();
}

然后你可以简单地将NetClassA和NetClassB的实例传递给MyMethod,如下所示:

var a = new NetClassA();
var b = new NetClassB();
MyMethod(a);
MyMethod(b);

这种方法的缺点是没有静态类型检查。如果NetClassA或NetClassB没有一个名为CommonMethod的方法没有接受任何参数,程序将编译,但在运行时失败。

此外,由于没有相关的界面,因此不清楚可用的功能和属性。避免在面向公众的程序集中使用此方法。