【问题标题】:How to create a variable of type that implement few interfaces (or subset of interfaces)?如何创建实现少数接口(或接口子集)的类型变量?
【发布时间】:2018-10-30 02:04:43
【问题描述】:

我有一个包含接口的第三方库(dll,使用 C# 创建)

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的方法并且不允许调用其他接口的方法的某种类型的变量

    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

但这意味着我必须从两个接口实现每个方法。 这种方案是不能接受的,因为实际上这些接口(@98​​7654342@,I2)包含了很多方法。


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

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

?

【问题讨论】:

  • 你确定你没有试图过度设计事情吗?我的意思是限制消费者对某些功能的访问是值得的,但是,我经常看到我的同事试图过度连接所有东西。也就是说,在我看来,界面最能描述通用性,不应该过多地用于限制访问或控制,尤其是当脏的小手指可以随意投掷时。
  • 接口不应该过多地用于限制访问或控制 - @TheGeneral,我同意,但需要防止调用某些函数,因为它们执行导致程序崩溃。

标签: c# inheritance types casting type-conversion


【解决方案1】:

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

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

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 'I' 不包含 'F3' 的定义并且没有扩展名 可以找到接受“I”类型的第一个参数的方法“F3”。

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

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

我们传递了一个C 类型的实例,它使用F3() 方法实现I3,但由于MySuperLogic 中定义的约束,您不能使用F3(),因为它不存在于@ 987654330@和I2

【讨论】:

    【解决方案2】:

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

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多