รับทุกประเภทที่ใช้อินเตอร์เฟส


553

ใช้การไตร่ตรองฉันจะทำให้ทุกประเภทที่ใช้อินเทอร์เฟซกับ C # 3.0 / .NET 3.5 มีโค้ดน้อยที่สุดและลดการทำซ้ำให้น้อยที่สุดได้อย่างไร

นี่คือสิ่งที่ฉันต้องการเขียนใหม่:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff

1
โค้ดตัวอย่างทำงานได้หรือไม่ ฉันมีเงื่อนไขที่เป็นลบกับคุณหากเงื่อนไข
Emperor Orionii

3
คำสั่ง if ในรหัสด้านบนจะเป็นเท็จเสมอเพราะคุณกำลังทดสอบว่าอินสแตนซ์ของประเภทคลาส (t) ใช้อินเทอร์เฟซของคุณซึ่งจะไม่ยกเว้นว่า Type จะสืบทอด IMyInterface (ซึ่งในกรณีนี้จะเป็นจริงเสมอ)
Liazy

คำตอบ:


807

ของฉันจะเป็นแบบนี้ใน 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.

194
โปรดทราบว่ารายการนี้อาจมีส่วนต่อประสานด้วยเช่นกัน เปลี่ยนบรรทัดสุดท้ายเป็น.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);เพื่อกรองออก (หรือp.IsClass)
jtpereyda

39
หมายเหตุ: คำตอบนี้ไม่ถูกต้อง! นี้จะตรวจสอบ "ความเข้ากันได้ที่ได้รับมอบหมาย" ไม่ว่าจะมีการใช้อินเตอร์เฟซจะไม่ ตัวอย่างเช่นList<string>ไม่ได้ใช้IEnumerable<object>แต่วิธีนี้จะกลับมาจริงใน. Net 4.0 เนื่องจากความแปรปรวนร่วมที่ผิดแน่นอน คำตอบที่ถูกต้องอยู่ที่นี่
Sriram Sakthivel

20
@SriramSakthivel ปิดก่อนไม่ได้ระบุค่าทั่วไป ประการที่สองคำถามนี้ล่วงหน้าวันที่ความแปรปรวนร่วม ประการที่สามคุณตั้งสมมติฐานว่าการคืนโควาเรียนต์ไม่ใช่สิ่งที่พวกเขาต้องการ
Darren Kopp

24
คุณน่ากลัวอย่างแน่นอนฉันรู้ว่านี่เป็นหัวข้อเก่าฉันเพิ่งลงทะเบียนความคิดเห็นของฉันสำหรับผู้ใช้ในอนาคตเพื่อให้ตระหนักถึงปัญหาดังกล่าว ไม่รุกรานคุณ และตามชื่อคำถามบอกว่าถ้า OP ขอให้รับทุกประเภทที่ใช้อินเทอร์เฟซรหัสนี้ไม่ได้ทำอย่างนั้น แต่มันก็ใช้ได้เกือบทุกกรณีไม่ต้องสงสัยเลย มีมุมตรงเหมือนที่ฉันพูด เพียงเพื่อให้ตระหนักถึงมัน
Sriram Sakthivel

9
จะต้องตรวจสอบให้แน่ใจว่าชั้นนั้นไม่เป็นนามธรรม =>.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
Jonesopolis

66

สิ่งนี้ใช้ได้สำหรับฉัน มันลูปแม้ว่าชั้นเรียนและตรวจสอบเพื่อดูว่าพวกเขาจะได้รับมาจาก myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }

5
คุณกำลังสมมติว่าแอสเซมบลีอยู่ในปฏิบัติการหลัก ไม่ใช่โครงการเพิ่มเติม คุณยังต้องวนซ้ำโดยไม่จำเป็นแม้ว่าจะเป็นการวนซ้ำ มันเป็นการดีกว่าที่จะมีกรอบทำการยกของหนัก จากนั้นกรองไกลขึ้นเมื่อพบ หากเกี่ยวข้องโปรดอัปเดตคำตอบของคุณ รวมรายการการใช้เหตุผล <T> var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies (). SelectMany (x => x.GetTypes ()) โดยที่ (mytype => typeof (myInterface) .IsAssignableFrom (mytype) &&tytypeInterface () )); foreach (รายการ var ในรายการ) Console.Log (item.Name);
TamusJRoyce

58

ในการค้นหาทุกประเภทในแอสเซมบลีที่ใช้อินเทอร์เฟซ 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 ซึ่งปัจจุบันถูกระบุว่าเป็นคำตอบนั้นไม่ถูกต้องเช่นกันและด้วยเหตุผลเดียวกัน ที่รันไทม์คุณจะเห็น 0 ประเภทกลับมาเพราะอินสแตนซ์ System.Type ทั้งหมดไม่ใช่ IFoo implementors


58

ฉันขอขอบคุณที่นี้เป็นคำถามที่เก่ามาก 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);

กล่าวอีกนัยหนึ่งClassBไม่สามารถโหลดได้ซึ่งเป็นสิ่งที่การเรียกไปยัง GetTypes ตรวจสอบและโยน

ดังนั้นเพื่อให้มีคุณสมบัติปลอดภัยชุดผลลัพธ์สำหรับประเภทที่โหลดได้แล้วตามบทความ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();
}

3
สิ่งนี้ช่วยให้ฉันจัดการกับปัญหาประหลาดสุด ๆ ในโครงการทดสอบของฉันที่ GetTypes จะล้มเหลวและเฉพาะในสภาพแวดล้อม CI ของเรา GetLoadableTypes เป็นวิธีแก้ไขสำหรับโซลูชันนี้ ข้อผิดพลาดจะไม่สามารถทำซ้ำได้ในสภาพแวดล้อมท้องถิ่นและนี่คือ: System.Reflection.ReflectionTypeLoadException: ไม่สามารถโหลดประเภทที่ร้องขอหนึ่งประเภทขึ้นไป ดึงข้อมูลคุณสมบัติ LoaderExceptions สำหรับข้อมูลเพิ่มเติม โดยเฉพาะอย่างยิ่งมันบ่นว่ามีประเภทที่ไม่ได้มีการใช้งานที่เป็นรูปธรรมและมันเกิดขึ้นในโครงการทดสอบหน่วย ขอบคุณสำหรับสิ่งนี้!
Lari Tuomisto

2
คำตอบนี้ควรถูกทำเครื่องหมายว่าเป็นวิธีแก้ปัญหาช่วยฉันในวันนี้เพราะอย่างเช่น @Lari Tuomisto กล่าวว่าบน env ท้องถิ่นเราไม่สามารถแก้ไขข้อผิดพลาดที่คล้ายกันได้
Lightning3

3
ในกรณีที่ช่วยคนอื่น: วิธีนี้ใช้ได้ผลสำหรับฉัน แต่ฉันต้องแก้ไขเพื่อลบประเภทอินเตอร์เฟสออกจากรายการ ฉันต้องการเปิดใช้งานCreateInstanceสำหรับพวกเขาทั้งหมดและมีข้อผิดพลาดเกิดขึ้นเมื่อพยายามสร้างอินเทอร์เฟซจริง (ซึ่งทำให้ฉันสับสนไประยะหนึ่งเมื่อฉันคิดว่าอินเทอร์เฟซที่เกิดขึ้นจริงไม่ได้อยู่ในโซลูชันนี้) GetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();ดังนั้นผมจึงเปลี่ยนรหัสเพื่อ
Xavier Peña

21

คำตอบอื่น ๆ IsAssignableFromที่นี่ใช้ นอกจากนี้คุณยังสามารถใช้FindInterfacesจากSystemnamespace ตามที่อธิบายไว้ที่นี่

นี่คือตัวอย่างที่ตรวจสอบแอสเซมบลีทั้งหมดในโฟลเดอร์ของแอสเซมบลีที่กำลังเรียกใช้งานอยู่ในปัจจุบันโดยมองหาคลาสที่ใช้อินเทอร์เฟซบางตัว (หลีกเลี่ยง 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();
}

คุณสามารถตั้งค่ารายการอินเตอร์เฟสหากคุณต้องการจับคู่มากกว่าหนึ่งรายการ


อันนี้จะมองหาชื่ออินเตอร์เฟสของสตริงซึ่งเป็นสิ่งที่ฉันกำลังมองหา
ส่ง

ทำงานเมื่อโหลดแอสเซมบลีในโดเมนอื่นเนื่องจากจะต้องมีการทำให้เป็นอนุกรมในสตริง สุดยอดมาก!
TamusJRoyce

ฉันได้รับ: ไม่สามารถแก้ไขการพึ่งพาแอสเซมบลี 'System.Core, เวอร์ชัน = 4.0.0.0, วัฒนธรรม = เป็นกลาง, PublicKeyToken = b77a5c561934e089' เพราะยังไม่ได้โหลดไว้ล่วงหน้า เมื่อใช้ ReflectionOnly APIs แอสเซมบลีที่ขึ้นต่อกันต้องถูกโหลดล่วงหน้าหรือโหลดตามต้องการผ่านเหตุการณ์ ReflectionOnlyAssemblyResolve
bkwdesign

18

วนลูปผ่านแอสเซมบลีที่โหลดทั้งหมดวนผ่านทุกประเภท

สิ่งที่ต้องการ:

Type ti = typeof(IYourInterface);
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            // here's your type in t
        }
    }
}

8

สิ่งนี้ใช้ได้กับฉัน (หากคุณต้องการคุณสามารถยกเว้นประเภทระบบในการค้นหา):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 

5

แก้ไข: ฉันเพิ่งเห็นการแก้ไขเพื่อชี้แจงว่าคำถามเดิมมีไว้เพื่อลดการวนซ้ำ / รหัสและนั่นก็เป็นเรื่องที่ดีและดีเหมือนการออกกำลังกาย แต่ในสถานการณ์จริงคุณจะต้องการการนำไปใช้ที่เร็วที่สุด ของ LINQ พื้นฐานที่ดูเท่เพียงใด

นี่คือวิธีการใช้งานของฉันสำหรับการวนซ้ำตามประเภทที่โหลด มันจัดการคลาสปกติรวมถึงอินเทอร์เฟซและตัวเลือก excluseSystemTypes จะเร่งความเร็วขึ้นอย่างมากหากคุณกำลังมองหาการใช้งานใน codebase ของคุณ / บุคคลที่สาม

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

มันไม่สวยฉันจะยอมรับ


2
ตัวแจงนับใช้ IDisposable ซึ่งไม่ได้ถูกกำจัดด้วยการลอง / ในที่สุด มันเป็นการดีกว่าที่จะใช้ foreach หรือ linq
TamusJRoyce

ทำไมคุณกำลังทดสอบexcludeSystemTypesสองครั้งในหนึ่งif?
NetMage

4

คำตอบอื่น ๆ ที่ไม่ได้ทำงานร่วมกับอินเตอร์เฟซทั่วไป

สิ่งนี้ทำเพียงแค่แทนที่ 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();

เพื่อให้พวกเขาอยู่ในรายการ


โปรดอธิบายว่าโซลูชันของคุณทำงานอย่างไรและทำไมจึงดีกว่าคำตอบอื่น ๆ ทั้งหมด
Lukas Körfer

มันไม่ได้เหนือกว่าหรือต่ำกว่าคำตอบอื่น ๆ ไม่ได้ผลสำหรับฉันและฉันก็อยากแบ่งปัน
Antonin GAVREL

ความคิดเห็นของฉันเกี่ยวกับคำตอบของคุณเป็นรหัสเท่านั้นดังนั้นฉันขอให้คุณเพิ่มคำอธิบายบางอย่าง
Lukas Körfer

2

ไม่มีวิธีง่ายๆ (ในแง่ของประสิทธิภาพ) ในการทำสิ่งที่คุณต้องการจะทำ

Reflection ทำงานกับแอสเซมบลีและชนิดเป็นหลักดังนั้นคุณจะต้องได้รับแอสเซมบลีทุกชนิด นี่คือตัวอย่าง:

Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);

คุณจะได้รับทุกประเภทที่ใช้ IMyInterface ใน Assembly MyAssembly


2

ดียิ่งขึ้นเมื่อเลือกสถานที่ประกอบ กรองแอสเซมบลีส่วนใหญ่ถ้าคุณรู้ว่าอินเทอร์เฟซที่นำมาใช้ทั้งหมดของคุณอยู่ภายใน AssemblyDefinedTypes เดียวกัน

// 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();

โดย Can Bilgin



1

มีคำตอบที่ถูกต้องอยู่แล้ว แต่ฉันต้องการเพิ่มการใช้ anther เป็นส่วนขยาย 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 { }
}

0
   public IList<T> GetClassByType<T>()
   {
        return AppDomain.CurrentDomain.GetAssemblies()
                          .SelectMany(s => s.GetTypes())
                          .ToList(p => typeof(T)
                          .IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface)
                          .SelectList(c => (T)Activator.CreateInstance(c));
   }

0

ฉันได้รับข้อยกเว้นใน linq-code ดังนั้นฉันจึงทำเช่นนี้ (ไม่มีส่วนขยายที่ซับซ้อน):

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

-3

คุณสามารถใช้ LINQ เพื่อรับรายการ:

var types = from type in this.GetType().Assembly.GetTypes()
            where type is ISomeInterface
            select type;

แต่จริงๆแล้วมันสามารถอ่านได้มากขึ้นหรือไม่


6
มันอาจจะอ่านได้มากกว่าถ้ามันใช้งานได้ น่าเสียดายที่ตำแหน่งของคุณกำลังตรวจสอบเพื่อดูว่าอินสแตนซ์ของคลาส System.Type ใช้ ISomeInterface ซึ่งจะไม่เป็นจริงเว้นแต่ ISomeInterface เป็น IReflect หรือ ICustomAttributeProvider จริง ๆ ซึ่งในกรณีนี้จะเป็นจริงเสมอ
Joel Mueller

คำตอบของ Carl Nayak ด้านบนมีคำตอบสำหรับการแก้ไขตำแหน่งคำสั่ง: IsAssignableFrom ความผิดพลาดง่าย ๆ สำหรับคำตอบ
TamusJRoyce
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.