C# 如何在泛型方法中获取具体类型
我有一个方法,返回实现接口的对象列表:C# 如何在泛型方法中获取具体类型,c#,reflection,types,C#,Reflection,Types,我有一个方法,返回实现接口的对象列表: private List<IFoo> GetData(string key) { ...returns a different concrete implementation depending on the key switch (key) { case "Bar": return new List<Bar>();//Bar:IFoo b
private List<IFoo> GetData(string key)
{
...returns a different concrete implementation depending on the key
switch (key)
{
case "Bar":
return new List<Bar>();//Bar:IFoo
break;
case "Foo":
return new List<Foo>();//Foo:IFoo
break;
case "FooBar":
return new List<FooBar>();//FooBar:IFoo
break;
//etc etc - (quite a lot of these)
}
}
internal interface IFoo
{
int ID { get; }
string Name { get; }
string Text { get; set; }
}
private DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
Type dataType;
if (data != null && data.Count() != 0)
{
//problem is typeof(T) is always IFoo - not FooBar
//typeof(T) will always return IFoo
//Will return the correct type
dataType = data.First().GetType();
}
else
{
return new DataTable();
//or throw ?
}
PropertyInfo[] properties = dataType.GetProperties();
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.DisplayName, prop.PropertyType);
}
//etc..
}
我对ConvertToDataTable的实现如下所示:
private DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
//problem is typeof(T) is always IFoo - not FooBar
PropertyInfo[] properties = typeof(T).GetProperties();
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.DisplayName, prop.PropertyType);
}
//etc..
}
私有数据表ConvertToDataTable(IEnumerable数据)
{
//问题是typeof(T)总是IFoo,而不是FooBar
PropertyInfo[]properties=typeof(T).GetProperties();
DataTable=新的DataTable();
foreach(属性中的var属性)
{
table.Columns.Add(prop.DisplayName、prop.PropertyType);
}
//等等。。
}
如何在泛型ConvertToDataTable方法中获取基础类型?GetType()是在运行时获取具体类的方法。你接受的答案是你所问问题的一个很好的解决方案
现在,从您试图完成的工作的角度来看,我想说明创建数据表并不需要RTTI。这里是ConvertToDataTable方法的一个实现,它“不在乎”t是什么,只要它实现了IFoo
private static DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
// Reflect the properties from T which is IFoo
PropertyInfo[] properties = typeof(T).GetProperties();
DataTable table = new DataTable();
// Add columns
foreach (var prop in properties)
{
table.Columns.Add(
prop.Name,
prop.PropertyType
).DataType = prop.PropertyType;
}
Console.WriteLine("Inside the generic method: ");
// Add rows
foreach (var item in data)
{
// RE: For "the question you asked": Use GetType() for object info.
Console.WriteLine("...the concrete Type is " + item.GetType().Name);
// I would ask, though, do you really need it for anything here?
// But for "the thing you're trying to accomplish" (making a DataTable)
// - This goes by the public properties declared in the interface IFoo.
// - It pulls properties GENERICALLY for ANY class that implements IFoo.
object[] values =
properties.Select(property => property.GetValue(item)).ToArray();
table.Rows.Add(values);
}
return table;
}
它可以传递包含完全不同类的IEnumerable,因为它们都实现了IFoo:
class FooA : IFoo
{
public int ID { get; } = 1;
public string Name { get; } = "I am Foo A";
public string Text { get; set; }
}
class FooB : IFoo
{
public int ID { get; } = 2;
public string Name { get; } = "I am Foo B";
public string Text { get; set; }
}
控制台输出:
Inside the generic method:
...the concrete Type is FooA
...the concrete Type is FooB
D I S P L A Y P O P U L A T E D T A B L E
ID Name Text
1 I am Foo A
2 I am Foo B
如果您想试用,可以从我们的GitHub下载。使用系统;
using System;
using System.Collections.Generic;
using System.Data;
namespace StackOverflow001
{
class Program
{
static void Main(string[] args)
{
var data = GetData("Foo");
var table = ConvertToDataTable(data);
data = GetData("Bar");
table = ConvertToDataTable(data);
data = GetData("FooBar");
table = ConvertToDataTable(data);
}
static IEnumerable<FooBase> GetData(string key) =>
key switch
{
"Foo" => new List<Foo>(),
"Bar" => new List<Bar>(),
"FooBar" => new List<FooBar>(),
_ => throw new ArgumentException(nameof(key)),
};
static DataTable ConvertToDataTable(IEnumerable<FooBase> data)
{
var properties = data switch
{
List<Foo> _ => typeof(Foo).GetProperties(),
List<Bar> _ => typeof(Bar).GetProperties(),
List<FooBar> _ => typeof(FooBar).GetProperties(),
_ => throw new ArgumentException(nameof(data)),
};
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.Name, prop.PropertyType);
}
return table;
}
}
interface IFoo {}
abstract class FooBase : IFoo { }
class Foo : FooBase { public int FooProp { get; set; } }
class Bar : FooBase { public int BarProp { get; set; } }
class FooBar : FooBase { public int FooBarProp { get; set; }}
}
使用System.Collections.Generic;
使用系统数据;
命名空间StackOverflow001
{
班级计划
{
静态void Main(字符串[]参数)
{
var数据=GetData(“Foo”);
var table=CONVERTODATABLE(数据);
数据=获取数据(“条形”);
table=ConvertToDataTable(数据);
数据=获取数据(“FooBar”);
table=ConvertToDataTable(数据);
}
静态IEnumerable GetData(字符串键)=>
钥匙开关
{
“Foo”=>新列表(),
“栏”=>新列表(),
“FooBar”=>新列表(),
_=>抛出新ArgumentException(nameof(key)),
};
静态数据表ConvertToDataTable(IEnumerable数据)
{
变量属性=数据开关
{
List=>typeof(Foo).GetProperties(),
List=>typeof(Bar).GetProperties(),
List=>typeof(FooBar).GetProperties(),
_=>抛出新ArgumentException(nameof(data)),
};
DataTable=新的DataTable();
foreach(属性中的var属性)
{
table.Columns.Add(prop.Name,prop.PropertyType);
}
返回表;
}
}
接口IFoo{}
抽象类FooBase:IFoo{}
类Foo:FooBase{public int FooProp{get;set;}
类栏:FooBase{public int BarProp{get;set;}
类FooBar:FooBase{public int FooBarProp{get;set;}
}
我认为在这种情况下,使用接口和泛型方法是个坏主意。使用继承可以使代码更简单、更清晰。将在编译时对其求值的typeof替换为在运行时对其求值的.GetType,您将得到coRect类型,而不是接口:
private List<IFoo> GetData(string key)
{
...returns a different concrete implementation depending on the key
switch (key)
{
case "Bar":
return new List<Bar>();//Bar:IFoo
break;
case "Foo":
return new List<Foo>();//Foo:IFoo
break;
case "FooBar":
return new List<FooBar>();//FooBar:IFoo
break;
//etc etc - (quite a lot of these)
}
}
internal interface IFoo
{
int ID { get; }
string Name { get; }
string Text { get; set; }
}
private DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
Type dataType;
if (data != null && data.Count() != 0)
{
//problem is typeof(T) is always IFoo - not FooBar
//typeof(T) will always return IFoo
//Will return the correct type
dataType = data.First().GetType();
}
else
{
return new DataTable();
//or throw ?
}
PropertyInfo[] properties = dataType.GetProperties();
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.DisplayName, prop.PropertyType);
}
//etc..
}
私有数据表ConvertToDataTable(IEnumerable数据)
{
类型数据类型;
if(data!=null&&data.Count()!=0)
{
//问题是typeof(T)总是IFoo,而不是FooBar
//typeof(T)将始终返回IFoo
//将返回正确的类型
dataType=data.First().GetType();
}
其他的
{
返回新的数据表();
//还是扔?
}
PropertyInfo[]properties=dataType.GetProperties();
DataTable=新的DataTable();
foreach(属性中的var属性)
{
table.Columns.Add(prop.DisplayName、prop.PropertyType);
}
//等等。。
}
在您的情况下,返回ConvertToDataTable(result)是否不可能?@osta这意味着在GetData方法中基于键以某种方式重复switch语句。我可以在调试器中看到具体类型。因此,如果我能以某种方式使用反射来实现这一点,那就太酷了——我可能需要使用GetData(string键,out类型)
和converttodataable(Type类型)
,而不是重新构造我的代码,但在我看来,这感觉不对,我没有意识到GetData中有一个switch语句。GetData可以是私有列表GetData(字符串键),其中T:IFoo代替并返回(切换后确定的类型)结果。@Ostas-我认为这不起作用,因为调用代码必须指定类型参数-因此它实际上是相同的issuep.s。我应该提到:您说FooA和FooB有不同的方法void ConcreteImplementation(){}的实现。只需在接口本身上调用该方法,就可以完全避免所有的麻烦和麻烦。换句话说:someFoo.ConcreteImplementation();如果您在接口中定义了正确的方法,那么它将调用正确的方法IFoo{void ConcreteImplementation();}(甚至有人可能会说这就是拥有接口的意义!)不能回答这个问题asked@Colin请听我说完,因为我只是想帮忙。如果问题是“如何从IEnumerable填充DataTable”,那么下面是一个完全充实的实现:。但您的问题被框定为“如何在泛型方法中获得具体类型”,您对此进行了评论“//问题是typeof(T)始终是IFoo-而不是FooBar”。我的答案是使用GetType(),它可以在任何地方(在泛型方法内部或外部)获得具体类型。我坚持我的回答!只要运行我的回购协议中的代码,我明白了。GetType可能是这个问题的最佳答案。是其他东西让我困惑。我不需要将单个项目转换为它们的具体类型-它们总是相同的具体类型。我已经编辑了我的问题以使其更清晰,如果你再次编辑你的问题,我将能够删除我的downvoteFair enoug