C#中"is"和"IsAssignableFrom"的区别是什么?

7
这句话的意思是“以下两者有何不同:”,可见它是一个问题。
typeof(IInterface).IsAssignableFrom(typeof(Class));

并且

typeof(Class) is IInterface

?

编辑:为了更好理解,我的功能大致如下:

public static List<T> GetAllInstancesOfType<T>() where T:Entity
{
  List<T> l = new List<T>();

  if (typeof(IMyInterface).IsAssignableFrom(typeof(T)) //or (typeof(T) is IMyInterface)
     foreach(Entity e in List1) if (e is T) l.Add(e as T);

  else foreach (Entity e in List2) if (e is T) l.Add(e as T);

  return l;
}

这可能会有用:https://dev59.com/kXA75IYBdhLWcg3w8-HZ - Mechanical Object
只有两个接口会返回true -- ICustomAttributeProviderIReflect - Austin Salonen
3个回答

14
他们看起来很相似,但在概念上有很大的区别。前者回答了这个问题:“如果我有一个这种类型的变量,我能否将其赋值为那种类型的?”
而后者回答了这个问题:“是否可以通过引用或装箱转换将此实际值转换为此类型?”
在后一种情况下,实际对象是Type类型的对象,而不是Class类型的对象。请确保您理解以下两者之间的区别:
Type t = typeof(Class);
Class c = new Class();
bool b1 = t is IInterface;
bool b2 = c is IInterface;

第一个问题是“可以将Type对象转换为接口吗?”第二个问题是“可以将Class对象转换为接口吗?”

我正在编写一个GetAllInstancesOfType<T>()风格的函数,并从T实现的接口中推断出要查找哪个列表中的Ts的信息(即,如果T实现了接口I,则在列表A中查找,否则在列表B中查找)。由于我只检查“T是否实现了I”,根据您的答案,我所说的是变量T是否可以分配类型I的值,而不是从I到T的转换 - 因此我应该使用选项1? - Haighstrom
@Haighstrom:我不太了解你的情况,无法给出建议,但是似乎有些奇怪。如果你想知道一个给定的“Type”是否表示实现了特定接口的类型,那么为什么要检查变量可分配性呢?变量与此有何关系?如果你想知道一个类型是否实现了一个接口,那么只需询问该类型其实现的接口列表即可!请记住,可分配性实现不一定是相同的东西。 - Eric Lippert
如果一个类型的实例实现了 IEnumerable<string> 接口,即使它没有显式地实现 IEnumerable<object> 接口,也可以将其分配给类型为 IEnumerable<object> 的变量。那么你更关心可分配性还是实现性呢? - Eric Lippert
我已经在原始帖子中添加了一个示例以提供上下文。我的方法是否有误? - Haighstrom
@Haighstrom:你的方法在我脑海中引起了警觉:每当你基于泛型类型参数给定的具体细节做出决策时,你编写的代码实际上并不符合泛型的精神。但我更关心的是你是否理解类型对象和该类型的实例之间的区别。问题“所有属于某个类型(比如老虎)的动物也都是哺乳动物吗?”和“这只具体的动物(一只老虎)是哺乳动物吗?”的答案相同:是的。问题“抽象概念‘老虎’是哺乳动物吗?”并非同一个问题。 - Eric Lippert
当你想到所有老虎的类时,脑海中浮现的那个概念并不会生下活体、长毛或产生自己的牛奶。那个“概念”不是哺乳动物。老虎的“描述”也不是哺乳动物;老虎才是哺乳动物。当你说 typeof(T) is IFoo 时,你要问的是什么--答案几乎肯定是“false”,因为“所有T的描述”不一定与实际的T有任何共同属性。 - Eric Lippert

3
一些区别:
A:使用IsAssignableFrom不需要任何对象实例(仅System.Type对象),这在反射期间非常有用。
B:使用“is”关键字,如果类型始终/从不兼容,可以获取一些编译时提示(至少使用resharper)。
C:它们有点相反。IsAssignableFrom检查传递为参数的类型的对象是否可以分配给其他类型的变量。关键字“is”检查左侧的对象是否可以分配给右侧关键字的类型的变量。

2

typeof(Class) is IInterface 总是会评估为 false,因为 typeof(Class) 的类型是 RuntimeType。正确的使用方式是在给定类的实例上使用,例如:

Class c = // something
bool isIt = c is IInterface;

is应该用于想要知道一个值是否可转换为在编译时已知的类型的情况。

IsAssignableFrom应该用于在运行时只知道一个或两个类型的情况。例如:someType.IsAssignableFrom(someOtherType)。如果两种类型在编译时都已知,例如:typeof(IInterface).IsAssignableFrom(typeof(Class));,则可以通过查找Class的定义来知道答案,在运行时检查它没有实际意义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接