根据T的不同内容返回List<T>

4
我想要做类似于这样的事情:
public List<T> GetList<T>()
{
    if (typeof(T) == typeof(Type1))
    {
        return new List<Type1>() { new Type1(), new Type1(), new Type1() };
    }

    if (typeof(T) == typeof(Type2))
    {
        return new List<Type2>() {new Type2(), new Type2()};
    }

    throw new Exception("Unknown T");
}

public void DoStuffWithGenericList<T>()
{
    var list = GetList<T>();
    // do stuff that does not depend on T
}

但那当然是不合法的。我感觉我在这里缺少一些基本的东西 :)

在我的情况下,我从Entity Framework获取了不同类型对象的列表,但我的其他逻辑并不依赖于实际类型。它可以仅使用List或可以是泛型。

所有作为类型参数调用GetList()的T都将继承自相同的基类(如果有区别的话)。


Type1和Type2是否相关?它们都可以从同一个父类派生吗? - mathk
如果您正在寻找一个真正通用的解决方案,可以创建T的新实例而不对它们施加约束,并且仍然相对快速,那么您可以使用编译的lambda表达式或IL。 - Daniel
6个回答

6
为什么不使用“new”操作符来实例化类型:
public List<T> GetList<T>() where T : new()
{
    if (typeof(T) == typeof(Type1)) 
    { 
        return new List<T>() { new T() }; 
    }                     
    // etc...
    throw new Exception("Unknown T");
}

您只需要添加new()约束条件,即可确保您的类型可以实例化。


根据类型,列表中的项目数量不同。 - Ilya Ivanov
那么您仍然可以通过检查类型来区分,但使用新的操作符。 - L-Four
或者接受一个 int 参数作为列表的大小。 - Paul Bellora

4

这种编程方式是无法运行的,因为它依赖于运行时类型检查(你已经明确地编写了它们)。但是在编译时,编译器怎么知道你的运行时检查的结果实际上是一个 List<T>

在这个特定的例子中,你可以通过以下方法实现所需的目标。

public List<T> GetList<T>() where T : new()
{
    if (typeof(T) == typeof(Type1))
    {
        return new List<T>() { new T(), new T(), new T() };
    }

    if (typeof(T) == typeof(Type2))
    {
        return new List<T>() { new T(), new T() };
    }

    throw new Exception("Unknown T");
}

当然,这并不能解决任何实际问题。如果您有任何特定的问题,而不是“为什么这不起作用”,请编辑问题进行提出。
请考虑:在您的代码中使用GetList时,您需要编写以下内容:
var x = GetList<SomeType>();

类型参数SomeType在调用处必须硬编码,否则程序将无法编译。但如果必须硬编码,则上述内容与以下内容没有任何区别

public List<SomeType> GetListOfSomeType() 
{
    return new List<SomeType>();
}

var x = GetListOfSomeType();

那么你到底想要实现什么目标呢?

当然,这个反例有点肤浅,在真实情况下,如果你愿意使用反射,GetList 的通用版本将允许更大的灵活性。但是再一次强调,在你的例子中并不是这种情况。


3
public List<T> GetList<T>() 
{
    if (typeof(T) == typeof(Type1))
    {
        return new List<Type1>() { new Type1(), new Type1(), new Type1() }.Cast<T>().ToList();
    }

    if (typeof(T) == typeof(Type2))
    {
        return new List<Type2>() {new Type2(), new Type2()}.Cast<T>().ToList();
    }

    throw new Exception("Unknown T");
}

这是我最喜欢的解决方案,但我还会在方法定义中添加一个 where T : Type1,Type2 子句,以确保大多数错误在编译时检测到。 - MarcF
1
@MarcF 类型约束列表最多只能包含一个(和任意数量的接口)。 - AakashM
@AakashM - 很好的澄清,所以它需要在T:IType1,IType2的位置。 - MarcF
@MarcF 这毫无意义 - 想想你在说什么。 - Paul Bellora

0
每当我要查看一个if(typeof(T) == typeof(SomeType),我就会切换到一个字典,它看起来更或多或少是这样的:
public static class ListCreator
{
    private static readonly Dictionary<Type, Func<object>> _Creators;

    static ListCreator()
    {
        _Creators = new Dictionary<Type, Func<object>>();
        InitializeDefaultCreators();
    }

    public static List<T> Create<T>()
    {
        Func<object> creator;

        if (!_Creators.TryGetValue(typeof(T), out creator))
        {
            throw new InvalidOperationException("No creator available for type " + typeof(T).FullName);
        }

        return (List<T>)creator();
    }

    public static void Register<T>(Func<List<T>> creator)
    {
        _Creators.Add(typeof(T), creator);
    }

    public static void Register(Type type, Func<object> creator)
    {
        _Creators.Add(type, creator);
    }

    public static bool Unregister<T>()
    {
        return _Creators.Remove(typeof(T));
    }

    public static bool Unregister(Type type)
    {
        return _Creators.Remove(type);
    }

    private static void InitializeDefaultCreators()
    {
        Register(MyDoubleListCreator);
        Register(typeof(int), () => Enumerable.Range(1, 15).ToList());
    }

    private static List<double> MyDoubleListCreator()
    {
        return Enumerable.Range(1, 10).Select(Convert.ToDouble).Select(val => val + 0.3).ToList();
    }
}

这可以用以下方式:

internal class Program
{
    private static void Main(string[] args)
    {
        ListCreator.Register(SelfMadeList);

        var someIntegers = ListCreator.Create<int>();
        foreach (var item in someIntegers)
        {
            Console.WriteLine("Some integer: " + item);
        }

        var someDoubles = ListCreator.Create<double>();
        foreach (var item in someDoubles)
        {
            Console.WriteLine("Some doubles: " + item);
        }

        var someTimeSpans = ListCreator.Create<TimeSpan>();
        foreach (var item in someTimeSpans)
        {
            Console.WriteLine("Some timespans: " + item);
        }

        Console.ReadKey();
    }

    private static List<TimeSpan> SelfMadeList()
    {
        return Enumerable.Range(1, 20)
                         .Select(Convert.ToDouble)
                         .Select(val => val + 0.5)
                         .Select(TimeSpan.FromHours)
                         .ToList();
    }
}

0

既然您已经检查过类型是否正确,那么只需将返回值转换即可:

return (List<T>)(object)new List<Type1>(...

-1
如果这些类型没有共同的父类,你可以返回一个 List<Object>,然后在使用它们时将各个元素进行强制转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接