简体   繁体   English

根据 Class 的类型创建通用 class 的实现实例<t></t>

[英]Create instance of implementation of generic class based on type of Class<T>

I have the following class layout:我有以下 class 布局:

abstract class GenericClass<TArgs> where TArgs : ArgsBaseClass { }
abstract class ArgsBaseClass { }

class RandomArgs : ArgsBaseClass { }
class RandomClass : GenericClass<RandomArgs> { }

Now I want to be able to create an instance of RandomClass from an instance of RandomArgs , without knowing that it should be RandomClass .现在我希望能够从RandomArgs的实例创建RandomClass的实例,而不知道它应该是RandomClass Ie somehow I need to derive the fact that RandomClass implements GenericClass<RandomArgs> .即不知何故,我需要得出RandomClass实现GenericClass<RandomArgs>的事实。

I'm able to create an instance of GenericClass<RandomArgs> using:我可以使用以下方法创建GenericClass<RandomArgs>的实例:

void CreateSpecificInstance(ArgsBaseClass args)
{
    Type genericType = typeof(GenericClass<>).MakeGenericType(typeof(args));
    var genericInstance = Activator.CreateInstance(genericType, typeof(args));
    // But then I need help for the following step:
    Type specificType = ...  // in this case RandomClass, but should be derived from 'args'.
    var specificInstance = (specificType)genericInstance;
}

Any help is appreciated.任何帮助表示赞赏。


EDIT:编辑:

Basically I have multiple args classes.基本上我有多个args类。 Each args class has a respective 'normal' class that can be initialised with this args class.每个args class 都有一个相应的“正常” class,可以使用此args class 进行初始化。 Hence GenericClass<ArgsBaseClass> .因此GenericClass<ArgsBaseClass>

Now I want to be able to create an instance of the 'normal' class whenever I pass an instance of the ArgsBaseClass to some function (in my example named CreateSpecificInstance .现在,每当我将ArgsBaseClass的一个实例传递给某个 function 时,我希望能够创建一个“正常” class 的实例(在我的示例中名为CreateSpecificInstance

As per my comments, I guess it would be possible to create a mapping between each args class and 'normal' class eg using a dictionary, but whenever you add a new args + 'normal' class combination you also need to update this dictionary.根据我的评论,我想可以使用字典在每个args class 和“正常”class 之间创建映射,但每当您添加新的args +“正常”ZA2F2ED4F8EBC2CBB4C21A29DC40 组合字典时,您还需要更新此组合字典。 Hence I guess a solution using reflection should be used here, however I don't see a solution using reflection that doesn't iterate over all classes in the assembly or namespace, hence I'm asking for help.因此,我想这里应该使用使用反射的解决方案,但是我没有看到使用反射的解决方案不会迭代程序集或命名空间中的所有类,因此我正在寻求帮助。

The most important thing to answer this question is a lot of really specific details, particular to your implementation.回答这个问题最重要的是很多非常具体的细节,特别是你的实现。

So, this answer is not a specific solution, but aims to describe a set of solutions, or at least ingredients for the solution.所以,这个答案不是一个具体的解决方案,而是旨在描述一组解决方案,或者至少是解决方案的成分。

The most difficult thing you can encounter in this kind of problems is dynamic discovery of interfaces and types.在这类问题中你可能遇到的最困难的事情是接口和类型的动态发现。 Eg you don't know at compile time the full list of Args types and GenericClass implementations.例如,您在编译时不知道Args类型和GenericClass实现的完整列表。

If you know it beforehand, you're lucky.如果你事先知道,你很幸运。 Just load a Dictionary<Type, Type> with the Args type as a key and the implementation type as value.只需加载一个Dictionary<Type, Type> ,其中Args类型作为键,实现类型作为值。

If you don't, you have an extra problem to solve: how to uniquely identify the implementation types?如果不这样做,你还有一个额外的问题要解决:如何唯一标识实现类型? There are many way to solve this problem, too, but they involve some form of Assembly.GetTypes() or (better yet) using a good IoC framework (i like Autofac the most) with built in assembly scanning capabilities.也有很多方法可以解决这个问题,但它们涉及某种形式的Assembly.GetTypes()或(更好的是)使用具有内置程序集扫描功能的良好 IoC 框架(我最喜欢Autofac )。 You would need to solve also the problem (maybe just in principle, but it's a question you need an answer for) of what happens if you find two implementations for the same args.如果您找到相同参数的两个实现,您还需要解决问题(可能只是原则上,但这是您需要回答的问题)。

Back to our implementation type.回到我们的实现类型。 We have an Args instance or type, we have our dictionary of types, so we find the Type of the correct implementation of GenericClass<TArgs> .我们有一个Args实例或类型,我们有我们的类型字典,所以我们找到了GenericClass<TArgs>正确实现的Type Now you need a way to build instances.现在您需要一种构建实例的方法。 If you can ensure you have a parameterless constructor, you can just call Activator.CreateInstance(myGenericType) .如果你可以确保你有一个无参数的构造函数,你可以调用Activator.CreateInstance(myGenericType) This will give you an instance of RandomClass , boxed inside an object .这会给你一个RandomClass的实例,装在object中。

You will need to cast it in some way, in order to use it, maybe to GenericClass<RandomArgs> .为了使用它,您需要以某种方式强制转换它,可能是GenericClass<RandomArgs>

If you do not have a parameterless constructor, and you can, try using an IoC container to make the hard work of discovering the constructor depencencies for you.如果您没有无参数构造函数,并且可以,请尝试使用 IoC 容器来为您发现构造函数依赖项进行艰苦的工作。 Again, Autofac is a nice candidate, but there are a lot of alternatives and this is a deep rabbit hole.同样, Autofac是一个不错的候选者,但有很多选择,这是一个很深的兔子洞。

So, in easiest case, you just need something like this:所以,在最简单的情况下,你只需要这样的东西:


private Dictionary<Type, Type> _implementations =
    new Dictionary<Type, Type>();

public void RegisterImplementation<TArgs, TImpl>()
    where TArgs : ArgsBaseClass
    where TImpl : GenericClass<TArgs>, new()
{
    _implementations[typeof(TArgs)] = typeof(TImpl);
}

public GenericClass<TArgs> MakeClass<TArgs>(TArgs args) where TArgs : ArgsBaseClass
{
    var implementationType = _implementations.TryGetValue(typeof(TArgs), out var t)
        ? t
        : throw new ArgumentException("The args type " + typeof(TArgs) + " is unrecognized.", nameof(args));

    return (GenericClass<TArgs>)Activator.CreateInstance(implementationType);
}

I have decided to go another route:我决定 go 另一条路线:

I have updated my ArgsBaseClass to the following:我已将我的ArgsBaseClass更新为以下内容:

abstract class ArgsBaseClass
{
    abstract Type InstanceType { get; }
}

now whenever I create a new implementation of this class I'm forced to do something like:现在,每当我创建此 class 的新实现时,我都被迫执行以下操作:

class RandomArgs : ArgsBaseClass 
{
    override Type InstanceType => typeof(RandomClass);
}

Then my CreateSpecificInstance becomes:然后我的CreateSpecificInstance变为:

void CreateSpecificInstance(ArgsbaseClass args)
{
    Type specificType = args.InstanceType;
    var specificInstance = (specificType)Activator.CreateInstance(specificType, args);
}

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

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