我有一个包含接口
的第三方库(使用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
允许调用所有接口的方法(F1
,F2
,F3
,...)。
要创建一个允许仅调用接口I1
的方法的变量,只需更改变量的类型
I1 c = new C();
c.F1(); // ok
// c.F2(); // error is ok
// c.F3(); // error is ok
但是现在我想创建一个允许调用接口I1
,I2
的方法的某种类型的变量,并且不允许调用其他接口的方法< / 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
(仅分别I1
和I2
)。
此问题的可能解决方案之一可能是类包装器
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
但这意味着我必须从两个接口实现每个方法。
这个解决方案是不可接受的,因为实际上这些接口(I1
,I2
)包含更多方法。
所以我的问题是: 如何创建一个允许我这样做的变量:
c.F1(); // ok
c.F2(); // ok
// c.F3(); // error is ok
吗
答案 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
}