返回泛型类型

时间:2016-08-19 22:42:01

标签: c# generics

我在C#中苦苦寻找泛型。考虑一下这段代码:

public interface A {};
public interface B : A {};
public interface C : A {};

public interface IMyInterface<in T> where T : A {};

public class FirstImpl<T> : IMyInterface<T> where T : B {};
public class SecondImpl<T> : IMyInterface<T> where T : C {};

现在我需要一些工厂,它接受一个类型并返回正确的实现:

public IMyInterface<T> Create<T>() where T : A 
{
    if(typeof(T) is B) {
        return new FirstImpl<T>();
    }
    if(typeof(T) is C) {
        return new SecondImpl<T>();
    }
}

这并不适用于两个层面。第一个是返回类型。第二个是我无法通过&#34; T&#34;进入第一个或第二个实现,因为它们需要更具体的类型。不知道怎么解决这个问题?

3 个答案:

答案 0 :(得分:3)

每当你有使用泛型类型或方法的代码,并且该代码对泛型类型参数进行某种测试时,你做错了。 (恕我直言,不言而喻,反思更糟糕。)泛型类型的全部意义在于编写不依赖于泛型类型的代码。

在您的示例中,更好的方法是这样的:

static IMyInterface<T> CreateB<T>() where T : B
{
    return new FirstImpl<T>();
}

static IMyInterface<T> CreateC<T>() where T : C
{
    return new SecondImpl<T>();
}

即。编写不同的方法来处理每个场景。如果基于约束的方法能够起作用,呼叫者将不得不知道它已经处理了什么。因此,只有具有不同的方法名称并不是问题,每个方法名称都适用于相应的情况。

如果以上内容无法解决您的具体情况,请改进问题,使其包含一个好的Minimal, Complete, and Verifiable code example,不仅会显示您尝试使用的通用类型,还会显示它们的上下文使用

答案 1 :(得分:2)

如果你不介意反思,你可以这样做:

public static IMyInterface<T> Create<T>() where T : A 
{
    if (typeof(B).IsAssignableFrom(typeof(T)))
    {
        var type = typeof(FirstImpl<>);
        var boundType = type.MakeGenericType(typeof(T));
        return (IMyInterface<T>) Activator.CreateInstance(boundType);
    }
    else if(typeof(C).IsAssignableFrom(typeof(T)))
    {
        var type = typeof(SecondImpl<>);
        var boundType = type.MakeGenericType(typeof(T));
        return (IMyInterface<T>) Activator.CreateInstance(boundType);
    }

    throw new ArgumentException("unknown type " + typeof(T).Name);
}

您可以在.net fiddle

中试用

答案 2 :(得分:1)

如果您想保持设计完整,最简单的方法是使用Create<T>()方法添加额外约束,例如public IMyInterface<T> Create<T>() where T : A , B, C。您可能需要一个默认情况的实现来使方法完成。

public IMyInterface<T> Create<T>() where T : A, B, C
{
    if (typeof(T) is B)
    {
        return new FirstImpl<T>();
    }
    if (typeof(T) is C)
    {
        return new SecondImpl<T>();
    }
    return new DefaultImpl<T>;
}