Development Tip

'open'제네릭 형식과 함께 IsAssignableFrom 사용

yourdevel 2020. 12. 30. 19:43
반응형

'open'제네릭 형식과 함께 IsAssignableFrom 사용


리플렉션을 사용하여 주어진 기본 클래스에서 상속되는 유형 집합을 찾으려고합니다. 단순한 유형을 알아내는 데 오래 걸리지 않았지만 제네릭에 관해서는 난처합니다.

이 코드의 경우 첫 번째 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>();
    }
}

그렇다면 하나의 제네릭 유형 정의가 다른 것에서 파생되었는지 런타임에 어떻게 결정합니까?


로부터 또 다른 질문에 대한 답변 :

public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
    var interfaceTypes = givenType.GetInterfaces();

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

    if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
        return true;

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

    return IsAssignableToGenericType(baseType, genericType);
}

(답이 마음에 들면 코드가 내 것이 아니기 때문에 링크 된 답변을 찬성하십시오.)


게시 한 정확한 코드는 놀라운 결과를 반환하지 않습니다.

이것은 "거짓"이라고 말합니다.

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

이것은 "true"라고 말합니다.

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

차이점은 개방형 제네릭 유형은 인스턴스를 가질 수 없으므로 하나가 다른 유형에 "할당"되지 않는다는 것입니다.

로부터 문서 :

반환 true하는 경우 c현재는 Type같은 유형을 표시, 또는 현재이 경우 Type의 상속 계층 구조에 c, 또는 현재이 경우 Type인터페이스가 그 c구현 경우, 또는 c제네릭 형식 매개 변수이며, 전류 Type의 제약 중 하나를 나타냅니다 c. false이러한 상황에 해당되지 않는 경우, 또는 경우가 c있습니다 null.

이 경우 이러한 조건 중 어느 것도 사실이 아닙니다. 추가 메모가 있습니다.

제네릭 형식 정의는 닫힌 생성 형식에서 할당 할 수 없습니다. 즉, 닫힌 생성 형식 MyGenericList<int>( MyGenericList(Of Integer)Visual Basic의 경우)을 형식의 변수에 할당 할 수 없습니다 MyGenericList<T>.


다음의 경우 Konrad Rudolph가 제공 한 메소드를 사용하면 다음과 같이 잘못 될 수 있습니다. IsAssignableToGenericType (typeof (A), typeof (A <>)); // return false

여기에 더 나은 대답이 있다고 생각합니다

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

자세한 내용 은 C # 제네릭과 함께 IsAssignableFrom 사용을 참조 하세요.

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

포함 된 유형을 비교해야합니다. 참조 : 제네릭 클래스 또는 메서드의 멤버에서 T 유형을 가져 오는 방법은 무엇입니까?

즉, 제네릭 클래스 자체가 아닌 제네릭 클래스에 포함 된 유형이 할당 가능한지 확인해야한다고 생각합니다.


I have a different Approach that resolves this issue, Here are my classes

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

Now if I have an instance of type OnClick but I dont know that, and I want to find out if I have an instance of anything which inherits from Signal<> of any type? I do this

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.

So this works for me, its not recursive, and it uses a trick via a designated property. It has limitations that its hard to write a function that checks assignability for all generics ever. But for a specific type it works

Obviously you need to check if() conditions better and stuff, but these are the Raw lines required to evaluate assignability of a type to its base generic, this way.

Hope this helps

ReferenceURL : https://stackoverflow.com/questions/5461295/using-isassignablefrom-with-open-generic-types

반응형