리플렉션을 사용하면 코드가 가장 적고 반복을 최소화하면서 C # 3.0 / .NET 3.5로 인터페이스를 구현하는 모든 유형을 어떻게 얻을 수 있습니까?
이것은 다시 작성하고 싶습니다.
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
리플렉션을 사용하면 코드가 가장 적고 반복을 최소화하면서 C # 3.0 / .NET 3.5로 인터페이스를 구현하는 모든 유형을 어떻게 얻을 수 있습니까?
이것은 다시 작성하고 싶습니다.
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
답변:
내 C # 3.0에서는 이것이 될 것입니다 :)
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
기본적으로 최소 반복 횟수는 항상 다음과 같습니다.
loop assemblies
loop types
see if implemented.
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
필터링 하려면 마지막 줄을 변경하십시오 (또는 p.IsClass
).
List<string>
구현하지 IEnumerable<object>
않지만이 메서드는 실제로 잘못된 공분산으로 인해 .Net 4.0에서 true를 반환합니다. 정답은 여기에 있습니다
.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
이것은 나를 위해 일했습니다. 클래스를 반복하고 myInterface에서 파생되었는지 확인합니다.
foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
.Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
//do stuff
}
IFoo 인터페이스를 구현하는 어셈블리에서 모든 유형을 찾으려면
var results = from type in someAssembly.GetTypes()
where typeof(IFoo).IsAssignableFrom(type)
select type;
Ryan Rinaldi의 제안이 잘못되었습니다. 0 유형을 반환합니다. 당신은 쓸 수 없습니다
where type is IFoo
type은 System.Type 인스턴스이고 IFoo 유형이 아니기 때문입니다. 대신 유형에서 IFoo를 할당 할 수 있는지 확인합니다. 예상 결과를 얻을 수 있습니다.
또한 현재 답변으로 표시되어있는 Adam Wright의 제안도 똑같은 이유로 잘못되었습니다. 모든 System.Type 인스턴스가 IFoo 구현자가 아니기 때문에 런타임에 0 유형이 다시 표시됩니다.
이 질문은 매우 오래된 질문이지만, 현재까지의 모든 답변은 어떤 형식을 사용하기 때문에 향후 사용자를위한 또 다른 답변을 추가 할 것이라고 생각했습니다 Assembly.GetTypes
.
GetTypes ()는 실제로 모든 유형을 반환하지만 반드시 유형을 활성화하여 잠재적으로을 던질 수 있음을 의미하지는 않습니다 ReflectionTypeLoadException
.
유형이 돌아 왔을 때 일 것 유형을 활성화 할 수있는하지 않는 전형적인 예이다 derived
에서 base
하지만 base
그와 다른 어셈블리에 정의되어 derived
, 호출 조립하지 않습니다 조립 것을 참조.
우리가 가지고 있다고 가정 해보십시오.
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
ClassC
어느 것이 안에 있다면 AssemblyC
우리는 받아 들여진 대답에 따라 무언가를합니다.
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
그런 다음을 던집니다 ReflectionTypeLoadException
.
이는에 대한 참조없이 AssemblyA
에 AssemblyC
당신이 할 수 없을 것입니다 :
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
다시 말해서 GetTypes에 대한 호출이 확인하고 던지는 ClassB
것은 로드 할 수 없습니다 .
따라서 Phil Haacked 기사 어셈블리 및 Jon Skeet 코드 에서 모든 유형 가져 오기 코드에 따라로드 가능한 유형에 대한 결과 집합을 안전하게 규정 하려면 대신 다음과 같이하십시오.
public static class TypeLoaderExtensions {
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null) throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
그리고:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
var it = typeof (IMyInterface);
return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}
CreateInstance
그들 모두 를 활성화 하고 싶었고 실제 인터페이스를 만들려고 할 때 예외가 발생했습니다 (실제 인터페이스 가이 솔루션에서 길을 벗어났다고 생각했을 때 잠시 혼란 스러웠습니다). 그래서 코드를로 변경했습니다 GetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
.
여기에 다른 답변이 사용 IsAssignableFrom
됩니다. 여기에 설명 된대로 네임 스페이스 FindInterfaces
에서 사용할 수도 있습니다 .System
다음은 현재 실행중인 어셈블리 폴더의 모든 어셈블리를 검사하여 특정 인터페이스를 구현하는 클래스를 찾는 예입니다 (명확성을 위해 LINQ 피하기).
static void Main() {
const string qualifiedInterfaceName = "Interfaces.IMyInterface";
var interfaceFilter = new TypeFilter(InterfaceFilter);
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var di = new DirectoryInfo(path);
foreach (var file in di.GetFiles("*.dll")) {
try {
var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName);
foreach (var type in nextAssembly.GetTypes()) {
var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
if (myInterfaces.Length > 0) {
// This class implements the interface
}
}
} catch (BadImageFormatException) {
// Not a .net assembly - ignore
}
}
}
public static bool InterfaceFilter(Type typeObj, Object criteriaObj) {
return typeObj.ToString() == criteriaObj.ToString();
}
둘 이상의 인터페이스를 일치 시키려면 인터페이스 목록을 설정할 수 있습니다.
편집 : 방금 원래 질문이 반복 / 코드 축소에 대한 것이고 운동으로 훌륭하고 훌륭하다는 것을 분명히하기 위해 편집을 보았습니다. 그러나 실제 상황에서는 가장 빠른 구현을 원할 것입니다. 기본 LINQ가 얼마나 멋진 지
다음은로드 된 유형을 반복하는 Utils 방법입니다. 인터페이스뿐만 아니라 일반 클래스를 처리하며 excludeSystemTypes 옵션은 자체 / 타사 코드베이스에서 구현을 찾고 있다면 작업 속도를 크게 향상시킵니다.
public static List<Type> GetSubclassesOf(this Type type, bool excludeSystemTypes) {
List<Type> list = new List<Type>();
IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator();
while (enumerator.MoveNext()) {
try {
Type[] types = ((Assembly) enumerator.Current).GetTypes();
if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) {
IEnumerator enumerator2 = types.GetEnumerator();
while (enumerator2.MoveNext()) {
Type current = (Type) enumerator2.Current;
if (type.IsInterface) {
if (current.GetInterface(type.FullName) != null) {
list.Add(current);
}
} else if (current.IsSubclassOf(type)) {
list.Add(current);
}
}
}
} catch {
}
}
return list;
}
예쁘지 않아요 인정 할게요
excludeSystemTypes
한 번에 두 번 테스트 if
합니까?
다른 답변은 일반 인터페이스에서 작동하지 않았습니다 .
이것은 typeof (ISomeInterface)를 typeof (T)로 대체합니다.
List<string> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
.Where(x => typeof(ISomeInterface).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.Select(x => x.Name).ToList();
그래서
AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
우리는 모든 어셈블리를 얻는다
!x.IsInterface && !x.IsAbstract
인터페이스와 추상 인터페이스를 제외하는 데 사용됩니다.
.Select(x => x.Name).ToList();
그것들을 목록에 넣으십시오.
수행하려는 작업을 수행하는 쉬운 방법은 없습니다 (성능 측면에서).
리플렉션은 주로 어셈블리 및 유형과 함께 작동하므로 모든 유형의 어셈블리를 가져 와서 올바른 인터페이스를 쿼리해야합니다. 예를 들면 다음과 같습니다.
Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);
그러면 어셈블리 MyAssembly에서 IMyInterface를 구현하는 모든 유형을 얻을 수 있습니다.
조립 위치를 선택할 때 더 좋습니다. 구현 된 모든 인터페이스가 동일한 Assembly.DefinedTypes 내에있는 경우 대부분의 어셈블리를 필터링하십시오.
// We get the assembly through the base class
var baseAssembly = typeof(baseClass).GetTypeInfo().Assembly;
// we filter the defined classes according to the interfaces they implement
var typeList = baseAssembly.DefinedTypes.Where(type => type.ImplementedInterfaces.Any(inter => inter == typeof(IMyInterface))).ToList();
OfType Linq 메소드는 다음과 같은 시나리오에 정확하게 사용될 수 있습니다.
https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
이미 유효한 답변이 많이 있지만 다른 시나리오를 보여주기 위해 Type 확장 및 단위 테스트 목록으로 다른 구현을 추가하고 싶습니다.
public static class TypeExtensions
{
public static IEnumerable<Type> GetAllTypes(this Type type)
{
var typeInfo = type.GetTypeInfo();
var allTypes = GetAllImplementedTypes(type).Concat(typeInfo.ImplementedInterfaces);
return allTypes;
}
private static IEnumerable<Type> GetAllImplementedTypes(Type type)
{
yield return type;
var typeInfo = type.GetTypeInfo();
var baseType = typeInfo.BaseType;
if (baseType != null)
{
foreach (var foundType in GetAllImplementedTypes(baseType))
{
yield return foundType;
}
}
}
}
이 알고리즘은 다음 시나리오를 지원합니다.
public static class GetAllTypesTests
{
public class Given_A_Sample_Standalone_Class_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(SampleStandalone);
_expectedTypes =
new List<Type>
{
typeof(SampleStandalone),
typeof(object)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Abstract_Base_Class_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(SampleBase);
_expectedTypes =
new List<Type>
{
typeof(SampleBase),
typeof(object)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Child_Class_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(SampleChild);
_expectedTypes =
new List<Type>
{
typeof(SampleChild),
typeof(SampleBase),
typeof(object)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Base_Interface_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(ISampleBase);
_expectedTypes =
new List<Type>
{
typeof(ISampleBase)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Child_Interface_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(ISampleChild);
_expectedTypes =
new List<Type>
{
typeof(ISampleBase),
typeof(ISampleChild)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Implementation_Class_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
protected override void Given()
{
_sut = typeof(SampleImplementation);
_expectedTypes =
new List<Type>
{
typeof(SampleImplementation),
typeof(SampleChild),
typeof(SampleBase),
typeof(ISampleChild),
typeof(ISampleBase),
typeof(object)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
public class Given_A_Sample_Interface_Instance_Type_When_Getting_All_Types
: Given_When_Then_Test
{
private Type _sut;
private IEnumerable<Type> _expectedTypes;
private IEnumerable<Type> _result;
class Foo : ISampleChild { }
protected override void Given()
{
var foo = new Foo();
_sut = foo.GetType();
_expectedTypes =
new List<Type>
{
typeof(Foo),
typeof(ISampleChild),
typeof(ISampleBase),
typeof(object)
};
}
protected override void When()
{
_result = _sut.GetAllTypes();
}
[Fact]
public void Then_It_Should_Return_The_Right_Type()
{
_result.Should().BeEquivalentTo(_expectedTypes);
}
}
sealed class SampleStandalone { }
abstract class SampleBase { }
class SampleChild : SampleBase { }
interface ISampleBase { }
interface ISampleChild : ISampleBase { }
class SampleImplementation : SampleChild, ISampleChild { }
}
linq 코드에 예외가 있으므로 복잡한 확장 없이이 방법으로 수행합니다.
private static IList<Type> loadAllImplementingTypes(Type[] interfaces)
{
IList<Type> implementingTypes = new List<Type>();
// find all types
foreach (var interfaceType in interfaces)
foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies())
try
{
foreach (var currentType in currentAsm.GetTypes())
if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract)
implementingTypes.Add(currentType);
}
catch { }
return implementingTypes;
}
LINQ를 사용하여 목록을 얻을 수 있습니다.
var types = from type in this.GetType().Assembly.GetTypes()
where type is ISomeInterface
select type;
그러나 실제로 더 읽기 쉬운가?