繁体   English   中英

C#:是具有继承的泛型类型的运算符

[英]C#: Is operator for Generic Types with inheritance

我有一个运算符比较泛型类型的问题。

 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

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

托比,提前谢谢

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

public interface ISomeInterface<out T> where T : SomeBaseClass

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

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

是的,您可以使用inout关键字来利用协方差和逆变:

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

这非常有用,因为它允许upcasts和downcasts没有任何问题和Compile-Time错误。

我不确定我是否正确理解了您的问题,但您可能需要在检查某个类是否派生自泛型类时得到答案:

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;
}

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

问:但是我如何检查它,如果我想为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构造的类型:

以及分别对IsGenericTypeIsGenericConstructedType进行的布尔前检查。

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

警告:检查空案例; 如果支持语言等,则使用null coalescing和/或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构造任何条件检查

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM