返回List <t>,具有不同的内容,具体取决于T </t>

时间:2013-05-30 12:21:08

标签: c# generics

我想做这样的事情:

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()的所有Ts将从相同的基类继承,如果它有所不同。

6 个答案:

答案 0 :(得分: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()约束来实例化您的类型。

答案 1 :(得分: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的通用版本如果你愿意使用反射,会增加灵活性。但同样,在你的例子中并非如此。

答案 2 :(得分: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");
}

答案 3 :(得分:0)

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

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

答案 4 :(得分: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();
    }
}

答案 5 :(得分:-1)

如果类型不是从公共类派生的,则可以返回List<Object>,然后在使用它们时转换单个元素。