简体   繁体   English

泛型派生类型的泛型方法返回对象

[英]Generic method returning objects of generic derrived types

I am struggling with generics in C# a little bit. 我在C#中的泛型方面有些挣扎。 Consider this piece of code: 考虑这段代码:

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 {};

now I need to some factory, which takes a type and returns the correct implementation: 现在我需要一些工厂,该工厂采用一种类型并返回正确的实现:

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>();
    }
}

this doesn't work on two levels. 这在两个层面上都不起作用。 the first one is return type. 第一个是返回类型。 The second one is that I can't pass "T" into first or second implementation, since they require more specific type. 第二个是我不能将“ T”传递到第一个或第二个实现中,因为它们需要更具体的类型。 Any idea how to solve this? 任何想法如何解决这个问题?

Any time you have code using a generic type or method, and that code does some sort of test on the generic type parameter, you're doing it wrong. 每当您使用通用类型或方法编写代码,并且该代码对通用类型参数进行某种测试时,您就做错了。 (And IMHO it goes without saying that dropping into reflection is even worse.) The whole point of a generic type is to write code that doesn't depend on the generic type. (恕我直言,不用说,反射会更糟。)泛型类型的全部要点是编写依赖于泛型类型的代码。

In your example, a better approach would be something like this: 在您的示例中,更好的方法是这样的:

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

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

Ie write different methods to handle each scenario. 即编写不同的方法来处理每种情况。 The caller is going to have to know what it's dealing with already anyway, if a constraint-based approach was going to work. 如果基于约束的方法行得通,则调用者无论如何都要知道正在处理什么。 So it's not a problem to just have different method names, each to be used in the appropriate and respective situation. 因此,仅使用不同的方法名称就不会有问题,每种方法名称都将在适当的情况下使用。

If the above does not address your specific scenario, please improve the question so that it includes a good Minimal, Complete, and Verifiable code example that shows not only the generic types you are trying to use, but also the context in which they will be used. 如果以上内容不能解决您的特定情况,请改进问题,使其包括一个良好的“ 最小,完整和可验证”代码示例 ,该示例不仅显示您尝试使用的泛型类型,还显示它们将在其中使用的上下文。用过的。

If you don't mind reflection, you could do it that way: 如果您不介意反思,可以这样做:

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);
}

You can try it in a .net fiddle 您可以在.net小提琴中尝试

The shortest way would be to just add the extra constraints with the Create<T>() method like public IMyInterface<T> Create<T>() where T : A , B, C if you want to keep the design intact. 最简单的方法是仅使用Create<T>()方法添加额外的约束,例如public IMyInterface<T> Create<T>() where T : A , B, C如果想要保持设计完整public IMyInterface<T> Create<T>() where T : A , B, Cpublic IMyInterface<T> Create<T>() where T : A , B, C You'd probably need one implementation for the default case to make the method complete. 对于默认情况,您可能需要一个实现来使方法完整。

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>;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM