如何在接口的空列表中获取对象类型

How to get type of objects in an empty list of an interface

考虑:

public interface I
{
    int InterfaceProperty {get;set;}
}

public class C1 : I
{
    public int InterfaceProperty {get;set;}
    public int Class1Property {get;set;}
}

public class C2 : I
{
    public int InterfaceProperty {get;set;}
    public int Class2Property {get;set;}
}

//In some other class:
public List<I> L;
void somemethod()
{
    this.L = new List<I>();
    this.L.Add(new C1());   //add some C1s into the list
    SomeMethodToGetProperties(L);
    this.L = new List<I>();
    this.L.Add(new C2());  //add some C2s into the list
    SomeMethodToGetProperties(L);
}

我需要 SomeMethodToGetProperties 获取 C1 或 C2 的属性列表。即,第一次调用 returns InterfaceProperty 和 Class1Property,第二次调用 returns InterfaceProperty 和 Class2Property。

我无法使用列表中的对象,因为列表可能是空的。我在列表上尝试了反射,但这只给了我接口的属性。

编辑:我原来写的方式无效。你做不到

this.L = new List<C1>()

你只能做类似的事情

this.L = new List<I>();
this.L.Add(new C1());

从列表本身的元数据看来,我需要的可能是不可能的。 所以我创建了第二个变量来保存我每次更改列表内容时设置的列表中项目的类型。

获取列表的实际类型:

Type listType = this.L.GetType();

获取它可以包含的对象类型:

Type elementType = listType.GetGenericArguments().Single();

获取该类型的属性:

var properties = elementType.GetProperties();

这是一个实现,扫描列表中的每个项目,并收集项目类型及其属性。这是因为每个列表可能有不止一种从接口继承的类型。

为了清楚起见,我重命名了界面并 类

结果是

Class1
        InterfaceProperty
        Class1Property

Class2
        InterfaceProperty
        Class2Property

使用代码:

public interface IInterface
{
    int InterfaceProperty { get; set; }
}

public class Class1 : IInterface
{
    public int InterfaceProperty { get; set; }
    public int Class1Property { get; set; }
}

public class Class2 : IInterface
{
    public int InterfaceProperty { get; set; }
    public int Class2Property { get; set; }
}

class Program
{
    public static List<IInterface> list;
    static void Main(string[] args)
    {
        list = new List<IInterface>();
        list.Add(new Class1());
        list.Add(new Class2());
        list.Add(new Class1());
        list.Add(new Class1());
        list.Add(new Class2());

        foreach (var itemType in GetItemTypeProperties(list))
        {
            Console.WriteLine(itemType.Key.Name);
            foreach (var property in itemType.Single())
            {
                Console.WriteLine($"\t{property.Name}");
            }
            Console.WriteLine();
        }
    }

    public static IEnumerable<IGrouping<Type,PropertyInfo[]>> GetItemTypeProperties<T>(List<T> list)
    {            
        var itemProperties = new Dictionary<Type, PropertyInfo[]>();
        foreach (var item in list)
        {
            var t = item.GetType();
            if (!itemProperties.ContainsKey(t))
            {
                itemProperties[t] = t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            }
        }
        return itemProperties.GroupBy(kv => kv.Key, kv=>kv.Value);
    }
}

您也可以获得相同的结果,方法是仅扫描列表中的第一项并假设其余项属于同一时间。这一次,就像你的问题一样,我用一组不同类型的新项目重新分配列表。

这会产生以下结果:

Class1
        InterfaceProperty
        Class1Property
Class2
        InterfaceProperty
        Class2Property

来自代码:

        list = new List<IInterface>();
        list.Add(new Class1());
        list.Add(new Class1());
        list.Add(new Class1());

        var item1 = list.First();
        var properties1 = item1.GetType().GetProperties();
        Console.WriteLine($"{item1.GetType().Name}");
        foreach (var prop in properties1)
        {
            Console.WriteLine($"\t{prop.Name}");
        }

        list = new List<IInterface>();
        list.Add(new Class2());
        list.Add(new Class2());

        var item2 = list.First();
        var properties2 = item2.GetType().GetProperties();
        Console.WriteLine($"{item2.GetType().Name}");
        foreach (var prop in properties2)
        {
            Console.WriteLine($"\t{prop.Name}");
        }