형식이 특정 일반 인터페이스 형식을 구현하는지 확인하는 방법


226

다음 유형 정의를 가정하십시오.

public interface IFoo<T> : IBar<T> {}
public class Foo<T> : IFoo<T> {}

맹 글링 된 유형 만 사용 가능한 경우 유형이 Foo일반 인터페이스를 구현 하는지 여부를 어떻게 알 IBar<T>수 있습니까?

답변:


387

TcK의 답변을 사용하여 다음 LINQ 쿼리로 수행 할 수도 있습니다.

bool isBar = foo.GetType().GetInterfaces().Any(x =>
  x.IsGenericType &&
  x.GetGenericTypeDefinition() == typeof(IBar<>));

1
이것은 매우 우아한 솔루션입니다! 내가 본 다른 것들은 foreach 루프 또는 더 긴 LINQ 쿼리를 사용합니다. 이 기능을 사용하려면 .NET Framework 3.5가 있어야합니다.
Daniel T.

7
나는 이것을 확장 방법으로 조금만 만드는 것이 좋습니다 .
브래드 헬러

1
필요에 따라 반환 된 인터페이스를 다시 사용해야 할 수도 있습니다.
Sebastian Good

4
나는 이것이 .net 내에서 훨씬 더 나은 ... 멤버 .Implements (IBar) 또는 CustomType.Implements (IBar)와 같은 핵심으로, 또는 더 나은 방법으로 키워드 "is"를 사용하여 구현되어야한다고 말하고 싶습니다. .. 나는 C #을 탐험하고 있으며 지금은 .net에서 조금 실망했습니다 ...
Sofija

2
약간의 추가 : IBar 여러 제네릭 형식이있는 경우, 당신은 표시하기 위해 필요한이 같은 typeof(IBar<,,,>)자리처럼 행동 쉼표로
롭 폰 Nesselrode

33

상속 트리를 살펴보고 트리에서 각 클래스의 모든 인터페이스를 찾고 인터페이스가 일반 인지 여부typeof(IBar<>) 를 호출 한 결과 와 비교 해야합니다 . 확실히 조금 아 ful니다.Type.GetGenericTypeDefinition

참조 이 대답 하고 이러한 것들을 더 많은 정보와 코드를.


왜 IBar <SomeClass>로 캐스팅하고 null을 확인하지 않습니까? (I 물론 '로'로 캐스팅 의미)
파블로 Retyk

5
T는 알 수 없으며 특정 유형으로 캐스트 할 수 없습니다.
sduplooy 2009

@ sduplooy : 어쩌면 나는 T를 알 수없는 방법을 놓치고 있습니까? 그것은 공용 클래스 푸를 컴파일 할 것 : IFoo <T> {}
파블로 Retyk

25
public interface IFoo<T> : IBar<T> {}
public class Foo : IFoo<Foo> {}

var implementedInterfaces = typeof( Foo ).GetInterfaces();
foreach( var interfaceType in implementedInterfaces ) {
    if ( false == interfaceType.IsGeneric ) { continue; }
    var genericType = interfaceType.GetGenericTypeDefinition();
    if ( genericType == typeof( IFoo<> ) ) {
        // do something !
        break;
    }
}

2
typeof (Foo)는 Foo를 설명하는 System.Type 개체를 반환하므로 GetType () 호출은 항상 System.Type에 대한 형식을 반환합니다. typeof (Foo) .GetInterfaces ()
Michael Meadows로

9

헬퍼 메소드 확장

public static bool Implements<I>(this Type type, I @interface) where I : class
{
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface)
        throw new ArgumentException("Only interfaces can be 'implemented'.");

    return (@interface as Type).IsAssignableFrom(type);
}

사용법 예 :

var testObject = new Dictionary<int, object>();
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!

2
"IsAssignableFrom"은 내가 찾던 것입니다-고마워
Jesper

22
제네릭 형식 매개 변수를 모르는 요구 자의 요구 사항에는 작동하지 않습니다. 예제에서 testObject.GetType (). Implements (typeof (IDictionary <,>)); 거짓을 반환합니다.
ctusch

@ctusch, 그렇다면 어떤 해결책이 있습니까?
Tohid

5

약간 간단한 버전의 @GenericProgrammers 확장 방법을 사용하고 있습니다.

public static bool Implements<TInterface>(this Type type) where TInterface : class {
    var interfaceType = typeof(TInterface);

    if (!interfaceType.IsInterface)
        throw new InvalidOperationException("Only interfaces can be implemented.");

    return (interfaceType.IsAssignableFrom(type));
}

용법:

    if (!featureType.Implements<IFeature>())
        throw new InvalidCastException();

5
일반 인터페이스에 대한 원래 질문의 요구 사항에 따라 여전히 작동하지 않습니다.
nathanchere

4

생성 된 일반 인터페이스 유형을 확인해야합니다.

다음과 같은 작업을 수행해야합니다.

foo is IBar<String>

IBar<String>생성 된 형식을 나타 내기 때문 입니다. 경우 때문에이 작업을 수행해야하는 이유는 T수표에 정의되지 뜻 경우, 컴파일러는 모르는 IBar<Int32>IBar<SomethingElse>.


4

완전히 형식 시스템을 해결하기 위해, 당신이 핸들 재귀, 예를 들어 필요가 있다고 생각 IList<T>: ICollection<T>: IEnumerable<T>당신이 모르는 것이다 않고, IList<int>궁극적으로 구현을 IEnumerable<>.

    /// <summary>Determines whether a type, like IList&lt;int&gt;, implements an open generic interface, like
    /// IEnumerable&lt;&gt;. Note that this only checks against *interfaces*.</summary>
    /// <param name="candidateType">The type to check.</param>
    /// <param name="openGenericInterfaceType">The open generic type which it may impelement</param>
    /// <returns>Whether the candidate type implements the open interface.</returns>
    public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType)
    {
        Contract.Requires(candidateType != null);
        Contract.Requires(openGenericInterfaceType != null);

        return
            candidateType.Equals(openGenericInterfaceType) ||
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) ||
            candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType));

    }

3

우선 public class Foo : IFoo<T> {}T 대신 클래스를 지정해야하기 때문에 컴파일하지 않지만 다음과 같은 작업을 수행한다고 가정합니다.public class Foo : IFoo<SomeClass> {}

그렇다면

Foo f = new Foo();
IBar<SomeClass> b = f as IBar<SomeClass>;

if(b != null)  //derives from IBar<>
    Blabla();

2

인터페이스뿐만 아니라 일반 기본 유형을 지원하는 확장 방법을 원한다면 sduplooy의 답변을 확장했습니다.

    public static bool InheritsFrom(this Type t1, Type t2)
    {
        if (null == t1 || null == t2)
            return false;

        if (null != t1.BaseType &&
            t1.BaseType.IsGenericType &&
            t1.BaseType.GetGenericTypeDefinition() == t2)
        {
            return true;
        }

        if (InheritsFrom(t1.BaseType, t2))
            return true;

        return
            (t2.IsAssignableFrom(t1) && t1 != t2)
            ||
            t1.GetInterfaces().Any(x =>
              x.IsGenericType &&
              x.GetGenericTypeDefinition() == t2);
    }

1

형식이 제네릭 형식을 상속하거나 구현하는지 확인하는 방법 :

   public static bool IsTheGenericType(this Type candidateType, Type genericType)
    {
        return
            candidateType != null && genericType != null &&
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType ||
             candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) ||
             candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType));
    }

0

다음 확장을 시도하십시오.

public static bool Implements(this Type @this, Type @interface)
{
    if (@this == null || @interface == null) return false;
    return @interface.GenericTypeArguments.Length>0
        ? @interface.IsAssignableFrom(@this)
        : @this.GetInterfaces().Any(c => c.Name == @interface.Name);
}

그것을 테스트합니다. 창조하다

public interface IFoo { }
public interface IFoo<T> : IFoo { }
public interface IFoo<T, M> : IFoo<T> { }
public class Foo : IFoo { }
public class Foo<T> : IFoo { }
public class Foo<T, M> : IFoo<T> { }
public class FooInt : IFoo<int> { }
public class FooStringInt : IFoo<string, int> { }
public class Foo2 : Foo { }

그리고 시험 방법

public void Test()
{
    Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
    Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
 }

-1

다음과 같은 문제가 없어야합니다.

bool implementsGeneric = (anObject.Implements("IBar`1") != null);

추가 크레딧을 얻으려면 IBar 쿼리에 특정 제네릭 형식 매개 변수를 제공하려는 경우 AmbiguousMatchException을 잡을 수 있습니다.


일반적으로 가능하면 문자열 리터럴을 사용하지 않는 것이 좋습니다. 이 접근법은 IBar 인터페이스의 이름을 바꾸면 문자열 리터럴이 변경되지 않으며 오류는 런타임에만 감지되므로 애플리케이션을 리팩토링하기가 더 어려워집니다.
andyroschy

'매직 문자열'등을 사용하는 것에 대한 위의 의견에 일반적으로 동의하는 한, 이것이 내가 찾은 가장 좋은 방법입니다. "IWhatever`1"과 동일한 PropertyType.Name에 대한 테스트는 충분히 가깝습니다.
nathanchere

왜 안돼? bool implementsGeneric = (anObject.Implements(typeof(IBar<>).Name) != null);
막심 젤리 나
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.