我遇到了is运算符比较泛型类型的问题。
public interface ISomeInterface<T> where T : SomeBaseClass{
}
public class SomeClass : SomeBaseClass{
}
现在我们想用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
是否可以检查变量泛型类型?
提前致谢, 托比
答案 0 :(得分:8)
这称为通用协方差,在C#4.0中受支持。您可以使用T
关键字标记通用out
参数:
public interface ISomeInterface<out T> where T : SomeBaseClass
但这有一个限制。 T
参数只能作为接口中方法的返回类型出现。
Eric Lippert对此主题有一个series of blog posts我邀请您阅读。
答案 1 :(得分:4)
是的,您可以使用in
和out
关键字来利用协方差和逆差:
public interface ISomeInterface<in T> where T : SomeBaseClass{
}
或者:
public interface ISomeInterface<out T> where T : SomeBaseClass{
}
但请记住,使用关键字in
可以使用 T 作为参数,否则使用out
可以使用 T 作为返回类型。
<强>协方差:强>
当您可以从X<S>
转换为X<B>
时,类型是协变的。
<强>逆变:强>
当您可以从X<B>
转换为X<S>
时,类型是逆变的。
- 其中S是子类,B是基类。
我在阅读C#4.0书时学到的一个有趣的例子是关于Stack。
class Stack<T>{
int i;
T[] array = new T[1000];
public void Push(T element){
array[i++] = element;
}
}
class BaseClass{
}
class SubClass : BaseClass{
}
事实上,它解释了在这种情况下可以使用逆变,当Stack实现这个接口时:
interface IPushable<in T>{
void Push(T element);
}
然后:
IPushable<BaseClass> stackB = new Stack<BaseClass>();
IPushable<SubClass> stackS = stackB;
stackS.Push(new SubClass());
虽然这种情况下的协方差,当Stack实现以下接口时:
interface IPoppable<in T>{
T Pop();
}
那么:
IPoppable<SubClass> stackS = new Stack<SubClass>();
IPoppable<BaseClass> stackB = stackB;
BaseClass baseClass = stackB.Pop();
这真的很有帮助,因为它允许没有任何问题和编译时错误的向上转发和向下转发。
答案 2 :(得分:1)
我不确定我是否正确理解了您的问题,但您可能需要Check if a class is derived from a generic class中的回答:
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur)
return true;
toCheck = toCheck.BaseType;
}
return false;
}
答案 3 :(得分:0)
答案从你的第二个问题开始,因为它似乎表明了你想要实现的目标:
问:但如果我希望IList<string>
的对象IList<object>
为真,我该如何检查?
您的推理似乎是因为字符串继承自object,您希望条件模式在一般情况下检查它。
IList<string> stringList = new List<string>();
IList<object> objectList = new List<object>();
stringList is IList<string>;
//> true
stringList is IList<object>;
//> false
objectList is IList<string>;
//> false
objectList is IList<object>;
//>true
"someString" is object
//> true
因此,您只需检查Generic-Type构造的类型:
分别对IsGenericType
或IsGenericConstructedType
进行布尔检查。
objectList.GetType().GenericTypeArguments[0] is object
//> true
stringList.GetType().GenericTypeArguments[0] is object
//> true
警告:检查空案例;如果支持语言,则使用null合并和/或空条件运算符等...为简洁和清晰起见,不在示例中
问:是否可以检查变量(继承)泛型类型?
除了Darin和fuex的答案之外,还有其他指示:
您可以使用Type
的IEquality实现进行严格的类型检查:
bool condition = (someObject != null
&& someObject.GetType().Equals(typeof(ISomeInterface<SomeClass>)) );
您明确检查接口:
var interfaces = someType.GetType().GetInterfaces();
//DotNet4.5: var interfaces = someType.GetType()
// .GetTypeInfo().ImplementedInterfaces;
bool condition = (interfaces != null && interfaces.ToList()
.Contains(typeof(ISomeInterface<SomeClass>)) == true);
您几乎可以使用Type和TypeInfo
构造任何条件检查