Tob*_*ias 3 c# generics operators
我有一个运算符比较泛型类型的问题.
public interface ISomeInterface<T> where T : SomeBaseClass{
}
public class SomeClass : SomeBaseClass{
}
Run Code Online (Sandbox Code Playgroud)
现在我们想用is运算符检查类型.我们有一个实现接口ISomeInterface的类的实例.
不幸的是,我们面临以下问题:
// someObject is an Instance of a class implementing interface ISomeInterface<SomeClass>
bool isSomeBaseClass = someObject is ISomeInterface<SomeBaseClass>; // false
bool isSomeClass = someObject is ISomeInterface<SomeClass>; // true
Run Code Online (Sandbox Code Playgroud)
是否可以检查变量泛型类型?
托比,提前谢谢
这称为通用协方差,在C#4.0中受支持.您可以T使用out关键字标记泛型参数:
public interface ISomeInterface<out T> where T : SomeBaseClass
Run Code Online (Sandbox Code Playgroud)
但这有一个限制.该T参数只能作为接口中方法的返回类型出现.
Eric Lippert有一系列有关此主题的博客文章,我邀请您阅读.
是的,您可以使用inandout关键字来利用协方差和逆变:
public interface ISomeInterface<in T> where T : SomeBaseClass{
}
Run Code Online (Sandbox Code Playgroud)
或者:
public interface ISomeInterface<out T> where T : SomeBaseClass{
}
Run Code Online (Sandbox Code Playgroud)
但请记住,使用关键字in您可以使用T作为参数,否则使用out您可以使用T作为返回类型。
协方差:
A型是协变的时候,你可以从转换X<S>到X<B>。
逆变:
A型逆变时,你可以从转换X<B>到X<S>。
- 其中 S 是子类,B 是基类。
我在阅读 C# 4.0 一书时学到的一个有趣的例子是关于堆栈。
class Stack<T>{
int i;
T[] array = new T[1000];
public void Push(T element){
array[i++] = element;
}
}
class BaseClass{
}
class SubClass : BaseClass{
}
Run Code Online (Sandbox Code Playgroud)
事实上,它解释了在这种情况下可以使用逆变,当 Stack 实现这个接口时:
interface IPushable<in T>{
void Push(T element);
}
Run Code Online (Sandbox Code Playgroud)
然后:
IPushable<BaseClass> stackB = new Stack<BaseClass>();
IPushable<SubClass> stackS = stackB;
stackS.Push(new SubClass());
Run Code Online (Sandbox Code Playgroud)
而协方差int这种情况,当Stack实现如下接口时:
interface IPoppable<in T>{
T Pop();
}
Run Code Online (Sandbox Code Playgroud)
那么:
IPoppable<SubClass> stackS = new Stack<SubClass>();
IPoppable<BaseClass> stackB = stackB;
BaseClass baseClass = stackB.Pop();
Run Code Online (Sandbox Code Playgroud)
这真的很有帮助,因为它允许向上转换和向下转换而不会出现任何问题和编译时错误。