简体   繁体   English

在非泛型类中创建泛型

[英]Creating Generics in Non-Generic Class

Firstly, I struggled with what to title this question, so please edit it if you think you've got a better idea. 首先,我很难为这个问题加上标题,因此,如果您认为自己有更好的主意,请对其进行编辑。

This seems to be a problem I run into now and again and end up doing something smelly to circumvent. 这似乎是我不时遇到的问题,并且最终做了臭味回避。 The general form seems to be that I have a non-generic class meant for getting an instance of something (ie a Factory) but there needs to be decisions made about what type the instance should have. 一般的形式似乎是我有一个非泛型类,用于获取某事物的实例(即Factory),但是需要确定该实例应具有的类型。 I think the example below illustrates what I'm going for, but you'll notice it doesn't compile because in the FooBarFactory I can't use AbstractThing for T as abstracts aren't allowed in that context. 我认为下面的示例说明了我要执行的操作,但是您会注意到它无法编译,因为在FooBarFactory我不能将AbstractThing用于T因为在该上下文中不允许使用AbstractThing So how can I let the FooBarFactory determine, at runtime, which type the Generator<T> should use for T? 因此,如何让FooBarFactory在运行时确定Generator<T>应该用于T的类型?

public class FooBarFactory
{
    private Generator<AbstractThing> _generator;

    public AbstractThing GetThing(string data, ThingType type)
    {
        switch (type)
        {
            case ThingType.Foo:
                _generator = new FooGenerator();
                break;

            case ThingType.Bar:
                _generator = new BarGenerator();
                break;

            case ThingType.None:
                return null;

            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
        }

        return _generator.Generate(data);
    }
}

public abstract class Generator<T> where T : AbstractThing, new()
{
    protected T GeneratedThing = new T();

    protected abstract void MapDataToThing(string data);

    public T Generate(string data)
    {
        MapDataToThing(data);
        return GeneratedThing;
    }
}

public class FooGenerator : Generator<Foo>
{
    protected override void MapDataToThing(string data)
    {
        GeneratedThing.AbstractProp = ParseAbstract(data);
        GeneratedThing.FooProp = ParseFoo(data);
    }

    private static string ParseAbstract(string data)
    {
        throw new NotImplementedException();
    }

    private static string ParseFoo(string data)
    {
        throw new NotImplementedException();
    }
}

public class BarGenerator : Generator<Bar>
{
    protected override void MapDataToThing(string data)
    {
        GeneratedThing.AbstractProp = "Base property in Bar";
        GeneratedThing.BarProp = data.Substring(4, 3);
    }
}

public abstract class AbstractThing
{
    public string AbstractProp { get; set; }
}

public class Foo : AbstractThing
{
    public string FooProp { get; set; }
}

public class Bar : AbstractThing
{
    public string BarProp { get; set; }
}

public enum ThingType
{
    None = 0,
    Foo = 1,
    Bar = 2
}

The main purpose of generics is to provide compile-time type safety. 泛型的主要目的是提供编译时类型的安全性。 It makes no sense to "let the FooBarFactory determine, at runtime, which type the Generator<T> should use for T ". “让FooBarFactory在运行时确定Generator<T>应该为T使用哪种类型”是没有意义的。

My intention was to enforce that the factory returns an AbstractThing. 我的意图是强制工厂返回AbstractThing。

This is enforced by the factory method having a return type of AbstractThing . 这由具有返回类型AbstractThing的factory方法实施。

What would you recommend here? 您会在这里推荐什么? Should the factory simply have a method for each subtype of AbstractThing? 工厂是否应该为AbstractThing的每个子类型简单地使用一种方法?

The GetThing method, ie the factory method, should simply return an AbstractThing based on some logic of yours, ie it is the non-generic factory itself that decides whether to return a Foo or a Bar object. GetThing方法(即工厂方法)应根据您的某些逻辑简单地返回AbstractThing ,即由非泛型工厂本身决定要返回Foo还是Bar对象。 Generics doesn't really apply here. 泛型在这里并不真正适用。

Or maybe should there be no instance of Generator in the factory, instead newing up the appropriate Generator within each case block? 也许在工厂中应该没有Generator的实例,而是在每个case块中更新适当的Generator?

You don't necessarily need any generator class. 您不一定需要任何生成器类。 You could implement the logic that decides whether a Foo or a Bar should be created directly in the factory method itself if you want to. 如果需要,您可以实现决定是否应在工厂方法本身中直接创建FooBar的逻辑。 The factory takes N number of parameters as input and return a concrete implementation of the AbstractThing type based on some logic that is abstracted away in the factory. 工厂将N个参数用作输入,并根据工厂中提取的某些逻辑返回AbstractThing类型的具体实现。

Hope that makes sense. 希望有道理。

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

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