4

我对比较泛型类型的 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

是否可以检查变量泛型类型?

在此先感谢,托比

4

4 回答 4

10

这称为泛型协方差,在 C# 4.0 中受支持。您可以使用关键字标记泛型T参数out

public interface ISomeInterface<out T> where T : SomeBaseClass

不过,这有一个限制。该T参数只能作为接口中方法的返回类型出现。

Eric Lippert 有一系列关于这个主题的博客文章,我邀请您阅读。

于 2012-06-25T09:21:15.400 回答
5

in是的,您可以使用andout关键字来利用协变和逆变:

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 的书时学到的一个有趣的例子是关于堆栈的。

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();

这真的很有帮助,因为它允许向上转换和向下转换而没有任何问题和编译时错误。

于 2012-06-25T09:23:10.697 回答
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;
}
于 2012-06-25T09:23:11.050 回答
0

答案从您的第二个问题开始,因为它似乎显示了您要实现的目标:

IList<string>问:但是,如果我想对is的对象求真,我该如何检查呢IList<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 构造的类型:

以及分别对IsGenericTypeor进行的布尔检查。IsGenericConstructedType

objectList.GetType().GenericTypeArguments[0] is object
//> true
stringList.GetType().GenericTypeArguments[0] is object
//> true

警告:检查空案例;如果在语言方面受支持,则使用 null 合并和/或 null 条件运算符等...为了简洁明了,示例中没有


问:是否可以检查变量(继承的)泛型类型?

除了 Darin 和 fuex 的答案之外,还有更多的指针:

  • 您可以使用 IEquality 实现Type进行严格的类型检查:

    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 构建任何条件检查

于 2016-07-28T07:06:34.207 回答