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 都将继承自同一个基类,如果它有所不同的话。

4

6 回答 6

6

为什么不使用“新”运算符来实例化类型:

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() 约束来实例化。

于 2013-05-30T12:25:44.377 回答
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如果您愿意使用反射,通用版本的 将允许更大的灵活性。但同样,在你的例子中,情况并非如此。

于 2013-05-30T12:25:44.233 回答
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");
}
于 2013-05-30T12:25:25.437 回答
0

只需转换返回值,因为您已经检查过以确保类型正确:

return (List<T>)(object)new List<Type1>(...
于 2013-06-06T05:56:46.097 回答
0

每当我要看到 a时,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();
    }
}
于 2013-06-06T07:41:36.133 回答
-1

如果类型不是从公共类派生的,则可以返回 a List<Object>,然后在使用单个元素时对其进行强制转换。

于 2013-05-30T12:26:06.383 回答