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