C# 将IsAssignableFrom与“open”泛型类型一起使用

C# 将IsAssignableFrom与“open”泛型类型一起使用,c#,generics,reflection,types,C#,Generics,Reflection,Types,使用反射,我试图找到从给定基类继承的类型集。没有花很长时间就搞清楚了简单类型,但当涉及到泛型时,我被难住了 对于这段代码,第一个IsAssignableFrom返回true,但第二个返回false。然而,最后的作业编写得很好 class class1 { } class class2 : class1 { } class generic1<T> { } class generic2<T> : generic1<T> { } class Program {

使用反射,我试图找到从给定基类继承的类型集。没有花很长时间就搞清楚了简单类型,但当涉及到泛型时,我被难住了

对于这段代码,第一个IsAssignableFrom返回true,但第二个返回false。然而,最后的作业编写得很好

class class1 { }
class class2 : class1 { }
class generic1<T> { }
class generic2<T> : generic1<T> { }

class Program
{
    static void Main(string[] args)
    {
        Type c1 = typeof(class1);
        Type c2 = typeof(class2);
        Console.WriteLine("c1.IsAssignableFrom(c2): {0}", c1.IsAssignableFrom(c2));

        Type g1 = typeof(generic1<>);
        Type g2 = typeof(generic2<>);
        Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));

        generic1<class1> cc = new generic2<class1>();
    }
}

那么,如何在运行时确定一个泛型类型定义是否派生自另一个泛型类型定义呢?

您需要比较包含的类型。见:

换句话说,我认为您需要检查泛型类所包含的类型是否可赋值,而不是泛型类本身。

来自:


如果你喜欢这个答案,请将链接的答案向上投票,因为代码不是我的。

你发布的确切代码不会返回令人惊讶的结果

这是假的:

Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
这是真的:

Type g1 = typeof(generic1<class1>);
Type g2 = typeof(generic2<class1>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
区别在于开放泛型类型不能有实例,因此一个实例不能分配给另一个实例

从:

如果c和当前 类型表示相同的类型,或者如果 当前类型位于 c的继承层次结构,或者如果 当前类型是一个接口 c实现的,或者如果c是 泛型类型参数和当前 类型表示一个 c的约束条件。如果没有,则为false 这些条件是真的,或者如果c 是空的

在这种情况下,这些条件显然都不成立。还有一个额外的注意事项:

不支持泛型类型定义 可从封闭结构中赋值的 类型也就是说,您不能分配 封闭构造型 MyGenericList MyGenericList将Visual Basic中的整数转换为 MyGenericList类型的变量


在以下情况下,使用Konrad Rudolph提供的方法可能是错误的,例如:IsAssignableTogenericTypeOfa,typeofA;//返回错误

我想这里有一个更好的答案

public static bool IsAssignableFrom(Type extendType, Type baseType)
{
    while (!baseType.IsAssignableFrom(extendType))
    {
        if (extendType.Equals(typeof(object)))
        {
            return false;
        }
        if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
        {
            extendType = extendType.GetGenericTypeDefinition();
        }
        else
        {
            extendType = extendType.BaseType;
        }
    }
    return true;
}
有关测试用例的详细信息,请参见

using System;

/**
 * Sam Sha - yCoder.com
 *
 * */
namespace Test2
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            string a = "ycoder";
            Console.WriteLine(a is object);
            A aa = new A();
            //Console.WriteLine(aa is A<>);//con't write code like this
            typeof(A<>).IsAssignableFrom(aa.GetType());//return false

            Trace(typeof(object).IsAssignableFrom(typeof(string)));//true
            Trace(typeof(A<>).IsAssignableFrom(typeof(A)));//false

            AAA aaa = new AAA();
            Trace("Use IsTypeOf:");
            Trace(IsTypeOf(aaa, typeof(A<>)));
            Trace(IsTypeOf(aaa, typeof(AA)));
            Trace(IsTypeOf(aaa, typeof(AAA<>)));

            Trace("Use IsAssignableFrom from stackoverflow - not right:");
            Trace(IsAssignableFrom(typeof(A), typeof(A<>))); // error
            Trace(IsAssignableFrom(typeof(AA), typeof(A<>)));
            Trace(IsAssignableFrom(typeof(AAA), typeof(A<>)));

            Trace("Use IsAssignableToGenericType:");
            Trace(IsAssignableToGenericType(typeof(A), typeof(A<>)));
            Trace(IsAssignableToGenericType(typeof(AA), typeof(A<>)));
            Trace(IsAssignableToGenericType(typeof(AAA), typeof(A<>)));
        }

        static void Trace(object log){
                Console.WriteLine(log);
        }

        public static bool IsTypeOf(Object o, Type baseType)
        {
            if (o == null || baseType == null)
            {
                return false;
            }
            bool result = baseType.IsInstanceOfType(o);
            if (result)
            {
                return result;
            }
            return IsAssignableFrom(o.GetType(), baseType);
        }

        public static bool IsAssignableFrom(Type extendType, Type baseType)
        {
            while (!baseType.IsAssignableFrom(extendType))
            {
                if (extendType.Equals(typeof(object)))
                {
                    return false;
                }
                if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
                {
                    extendType = extendType.GetGenericTypeDefinition();
                }
                else
                {
                    extendType = extendType.BaseType;
                }
            }
            return true;
        }

        //from stackoverflow - not good enough
        public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
            var interfaceTypes = givenType.GetInterfaces();

            foreach (var it in interfaceTypes)
                if (it.IsGenericType)
                    if (it.GetGenericTypeDefinition() == genericType) return true;

            Type baseType = givenType.BaseType;
            if (baseType == null) return false;

            return baseType.IsGenericType &&
                baseType.GetGenericTypeDefinition() == genericType ||
                IsAssignableToGenericType(baseType, genericType);
        }
    }

    class A{}
    class AA : A{}
    class AAA : AA{}
}

我有一种不同的方法来解决这个问题,下面是我的类

public class Signal<T>{
   protected string Id {get; set;} //This must be here, I use a property because MemberInfo is returned in an array via GetMember() reflection function
   //Some Data and Logic And stuff that involves T
}

public class OnClick : Signal<string>{}
现在,如果我有一个OnClick类型的实例,但我不知道,我想知道我是否有一个从任何类型的Signal继承的任何东西的实例?我这样做

Type type = GetTypeWhomISuspectMightBeAGenericSignal();

PropertyInfo secretProperty = type.GetProperty("Id", BindingFlags.NonPublic | BindingFlags.Instance);

Type SpecificGenericType = secretProperty.DeclaringType; //This is the trick

bool IsMyTypeInheriting = SpecificGenericType.IsGenericType && SpecificGenericType.GetGenericTypeDefinition() == typeof(Signal<>); //This way we are getting the genericTypeDefinition and comparing it to any other genericTypeDefinition of the same argument length.
这对我来说是可行的,它不是递归的,它通过指定的属性使用技巧。它的局限性在于很难编写一个函数来检查所有泛型的可分配性。但对于一种特定的类型,它是有效的

显然,您需要检查条件是否更好,但这些是评估类型对其基本泛型的可分配性所需的原始行


希望这对我的两分钱有帮助。我认为将IsAssignableFrom的实现、派生或原始功能分开没有多大意义

根据前面给出的答案,我是这样做的:

public static bool implementorderivesthis@this,Type from { iffrom为空 { 返回false; } 否则,如果!from.IsGenericType { 从……回来。IsAssignableFrom@this; } else if!from.IsGenericTypeDefinition { 从……回来。IsAssignableFrom@this; } 否则,如果从i界面 { @this.GetInterfaces中的foreachType@interface { if@interface.IsGenericType&&&@interface.GetGenericTypeDefinition==来自 { 返回true; } } } if@this.IsGenericType&&&@this.GetGenericTypeDefinition==发件人 { 返回true; } 返回@this.BaseType?.ImplementorDerivesFrom??false; }
@konrad_ruldolph的答案基本上是正确的,但它要求您知道基本类型/接口是一个开放泛型。我提出了一个改进,将非泛型测试与循环相结合,以测试泛型匹配

公共静态类Ext { 公共静态布尔是可识别的通用布尔 此类型可从, 可分配给的类型 { 布尔ISTYPE比较表 =>assignableTo.IsAssignableFromcomparand ||comparand.IsGenericType &&comparand.GetGenericTypeDefinition==可分配给; 而assignableFrom!=null { 如果IsTypeassignableFrom ||可转让自 .GetInterface .任何类型 { 返回true; } assignableFrom=assignableFrom.BaseType; } 返回false; } }
最后的作业只涉及一般2…可能是@Daniel Hilgarth的副本-谢谢!我在发布前清理示例代码时错过了这一点。当赋值为generic1 cc=new generic2时,它仍然编译;当然可以编译;-问题是,一般来说,generic1不可分配给generic2,这就是您在调用typ时忽略generic参数的问题
eof。仅当generic1和generic2的泛型参数相同时,该参数才可赋值。如何解决这个问题?见康拉德·鲁道夫的答案。谢谢!这正是我想要的。在前面查看时,我没有注意到其他问题。在以下情况下,此方法可能是错误的:IsAssignableToGenericTypeOfa,typeofA;//返回错误尽管这个答案很好,但在使用它时要小心。我使用它,让布尔表达式工作,然后我什么都做不了,因为我可以投射我的对象来使用它。。。我必须引入一个接口,我可以简单地用它来检查…基于这个方法,我创建了一个不同的方法来获取用于基类型的泛型参数:注意,这比它需要的更昂贵,因为它对每个基类型迭代一次接口列表,这是不必要的。注意:这个答案不处理通用接口。很好的解释!
Type type = GetTypeWhomISuspectMightBeAGenericSignal();

PropertyInfo secretProperty = type.GetProperty("Id", BindingFlags.NonPublic | BindingFlags.Instance);

Type SpecificGenericType = secretProperty.DeclaringType; //This is the trick

bool IsMyTypeInheriting = SpecificGenericType.IsGenericType && SpecificGenericType.GetGenericTypeDefinition() == typeof(Signal<>); //This way we are getting the genericTypeDefinition and comparing it to any other genericTypeDefinition of the same argument length.