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