如何创建实现少量接口(或接口子集)的类型变量?

时间:2018-05-20 03:52:26

标签: c# inheritance types casting type-conversion

我有一个包含接口

的第三方库(使用C#创建的dll)
public interface I1 {
    void F1();
}
public interface I2 {
    void F2();
}
public interface I3 {
    void F3();
}
// and so on ...

并包含一个类

public class C : I1, I2, I3 // ...
{
    public void F1() { }    // implement I1.F1();
    public void F2() { }    // implement I2.F2();
    public void F3() { }    // implement I3.F3();
    // and so on ...
}

我在VisualStudio的项目中添加了对此库的引用,并创建了类C的实例

C c = new C();
c.F1();    // ok
c.F2();    // ok
c.F3();    // ok

变量c允许调用所有接口的方法(F1F2F3,...)。

要创建一个允许仅调用接口I1的方法的变量,只需更改变量的类型

    I1 c = new C();
    c.F1();    // ok
//  c.F2();    // error is ok
//  c.F3();    // error is ok

但是现在我想创建一个允许调用接口I1I2的方法的某种类型的变量,并且不允许调用其他接口的方法< / p>

    I1_I2 c = new C();
    c.F1();    // ok
    c.F2();    // ok
//  c.F3();    // error is ok

为此,我创建了界面

public interface I1_I2 : I1, I2 { }

但是,编译器不允许我进行分配

I1_I2 c = new C();    // Compile error : Cannot implicitly convert type 'C' to 'I1_I2'.

我尝试过显式转化

I1_I2 c = (I1_I2)new C();    // Runtime error : InvalidCastException was unhandled.

但无法执行此转换,因为类C未实现I1_I2(仅分别I1I2)。

此问题的可能解决方案之一可能是类包装器

public class Wrapper : I1_I2
{
    private C _c = new C();
    public void F1() { _c.F1(); }
    public void F2() { _c.F2(); }
}
// ---------------------------------
    I1_I2 c = new Wrapper();
    c.F1();    // ok
    c.F2();    // ok
//  c.F3();    // error is ok

但这意味着我必须从两个接口实现每个方法。 这个解决方案是不可接受的,因为实际上这些接口(I1I2)包含更多方法。

所以我的问题是: 如何创建一个允许我这样做的变量:

    c.F1();    // ok
    c.F2();    // ok
//  c.F3();    // error is ok

2 个答案:

答案 0 :(得分:2)

正如您在问题中所说,您可以使用包装类,但您不喜欢它。另一种解决方案是使用逻辑的方法是具有一些约束的通用方法。

所以,假设你有一个实际上看起来像这样的方法:

public void MySuperLogic()
{
    C c = new C();
    c.F1();
    c.F2(); 
    c.F3();
}

您不希望允许调用C.F3()方法,因此带有约束的通用方法可以通过重构下面的方法来提供帮助:

public void MySuperLogic<I>(I c) 
    where I: I1, I2 // <- The generic type parameter should implement interfaces I1 and I2.
{
    c.F1();
    c.F2(); 
    c.F3(); // <-- CS1061 : Compile time error.
}

CS1061是一个编译时错误,它告诉你:

  

CS1061'我'不包含'F3'的定义,也没有扩展名   可以找到方法'F3'接受类型'I'的第一个参数。

您可以这样调用您的方法:

var c = new C();
MySuperLogic(c);

我们传递了C类型的实例,该实例使用I3方法实现F3(),但由于MySuperLogic中定义的约束,您不能使用{{1}因为它不存在于F3()I1

答案 1 :(得分:0)

在这种情况下,也许最好的解决方案是

public interface I1_I2 : I1, I2 { }

public class C_I1_I2 : C, I1_I2 { }

public static void Main() {
    I1_I2 c = new C_I1_I2();
    c.F1();    // ok
    c.F2();    // ok
//  c.F3();    // error is ok
}

Source