如何访问List <t>的属性,其中T每次都是不同的对象

时间:2019-04-06 20:15:59

标签: c#

如何访问List<T>的属性,其中T每次都是对象,学生,产品等的另一种类型?问题在于,在编译时C#无法识别T中包含的属性。如您所见(如代码中的注释所示),我制作了foreach,然后在尝试{{ 1}},则不会显示该对象的属性。

itemList

5 个答案:

答案 0 :(得分:3)

什么是泛型

泛型背后的想法是,它们对传递给它的所有内容都执行相同的操作。例如,可以编写通用函数来对任何类型的列表进行计数,因为可以对所有列表进行计数。

int GetCount<T>(List<T> source)
{
    return source.Count();
}

哪些通用名称不适用

如果您必须对不同的类型做不同的事情,那么泛型不是正确的答案。处理它的典型方法是使用不同的函数,每个函数都接受与其逻辑匹配的类型。如果需要,这些函数可以具有相同的名称(称为method overloading)。

void Print(List<Student> list)
{
    foreach(var item in list)
    {
        Console.WriteLine("{0}", item.Id);
    }
}

void Print(List<Admin> list)
{
    foreach(var item in list)
    {
        Console.WriteLine("{0}", item.Name);
    }
}

如何使一个以上类的方法通用

如果您偶然发现某些对象具有相同的属性,则可以为它们提供一个包含一个或多个公共属性的公共接口:

interface IHasName
{
    string Name { get; }
}

class Admin : IHasName
{
    public string Name { get; set; }
}

class Student: IHasName
{
    public string Name { get; set; }
}

如何显示属性

一旦有了公共接口,就可以使用type constraint编写通用方法,并且您的属性将突然对您可用。只有那些由类型约束保证存在的属性才可用;这使通用方法具有类型安全性。

public void Print<T>(List<T> source) where T : IHasName
{
    foreach (var item in source)
    {
        Console.WriteLine("{0}", item.Name);
    }
}

另一种解决问题的方法

处理此类问题的另一种方法是提供通用回调。

void Print<T>(List<T> source, Func<T,string> callback)
{
    foreach (var item in source)
    {
        Console.WriteLine("{0}", callback(item));
    }
}

然后这样称呼它:

var list = new List<Student>();
Print(list, item => item.Id.ToString());

var list2 = new List<Admin>();
Print(list2, item => item.Name);

之所以可行,是因为访问属性的逻辑包含在您的回调中,而不是包含在泛型方法中,从而避免了该问题。

答案 1 :(得分:1)

如果您的对象没有共同点,并且您不想使用Polymorphism,则一定要使用System.Reflection

public void Print<T>(List<T> list)
{
    foreach (var itemList in list)
    {
        var properties = typeof(T).GetProperties();
        var values = properties.Select(x => x.GetValue(itemList));
        Console.WriteLine(string.Join(",", values));
    }
}

您不再需要将方法定义为generic

答案 2 :(得分:0)

John Wu的答案提供了一些很好的建议-在这种情况下,值得注意的是,您不需要使用泛型来完全完成所需的操作,只需使用非泛型接口并将它们作为对象实例进行交互即可:

    static void Print(IEnumerable data)
    {

        foreach (var item in data)
        {
            switch (item)
            {
                case String str:
                    Console.WriteLine(str);
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }

答案 3 :(得分:-1)

我建议覆盖您班上的ToString()-方法:

public class Student
{
    public int Id { get; set; }
    public override string ToString()
    {
        return Id?.ToString();
    }
}

public class Admin
{
    public string Name { get; set; }
    public override string ToString()
    {
        return Name;
    } 
}

public class Generic
{
    public void Print<T>(List<T> list)
    {
        foreach (var item in list)
        {
            Console.WriteLine(item); // Implicitly calls ToString()
        }
    }
}

答案 4 :(得分:-1)

如果泛型类列表有限,则可以使用此选项。我会推荐@Bercovici Adrian的答案。无论如何,我会给出另一种方式。

在使用as找到正确的类型之后,可以使用c#if运算符将列表转换为其非通用成员。

public class Generic
    {
        public void Print<T>(List<T> list)
        {
            if(list is List<Student>)
            {
                var studentList = list as List<Student>;
                foreach (var itemList in studentList)
                {
                    Console.WriteLine(itemList.Id);
                }
            }
            else if(list is List<Product>)
            {
                var productList = list as List<Product>;
                foreach(var itemList in productList)
                {
                    Console.WriteLine(itemList.Price);
                }
            }
        }
    }