繁体   English   中英

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

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

我有以下 class 布局:

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

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

现在我希望能够从RandomArgs的实例创建RandomClass的实例,而不知道它应该是RandomClass 即不知何故,我需要得出RandomClass实现GenericClass<RandomArgs>的事实。

我可以使用以下方法创建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;
}

任何帮助表示赞赏。


编辑:

基本上我有多个args类。 每个args class 都有一个相应的“正常” class,可以使用此args class 进行初始化。 因此GenericClass<ArgsBaseClass>

现在,每当我将ArgsBaseClass的一个实例传递给某个 function 时,我希望能够创建一个“正常” class 的实例(在我的示例中名为CreateSpecificInstance

根据我的评论,我想可以使用字典在每个args class 和“正常”class 之间创建映射,但每当您添加新的args +“正常”ZA2F2ED4F8EBC2CBB4C21A29DC40 组合字典时,您还需要更新此组合字典。 因此,我想这里应该使用使用反射的解决方案,但是我没有看到使用反射的解决方案不会迭代程序集或命名空间中的所有类,因此我正在寻求帮助。

回答这个问题最重要的是很多非常具体的细节,特别是你的实现。

所以,这个答案不是一个具体的解决方案,而是旨在描述一组解决方案,或者至少是解决方案的成分。

在这类问题中你可能遇到的最困难的事情是接口和类型的动态发现。 例如,您在编译时不知道Args类型和GenericClass实现的完整列表。

如果你事先知道,你很幸运。 只需加载一个Dictionary<Type, Type> ,其中Args类型作为键,实现类型作为值。

如果不这样做,你还有一个额外的问题要解决:如何唯一标识实现类型? 也有很多方法可以解决这个问题,但它们涉及某种形式的Assembly.GetTypes()或(更好的是)使用具有内置程序集扫描功能的良好 IoC 框架(我最喜欢Autofac )。 如果您找到相同参数的两个实现,您还需要解决问题(可能只是原则上,但这是您需要回答的问题)。

回到我们的实现类型。 我们有一个Args实例或类型,我们有我们的类型字典,所以我们找到了GenericClass<TArgs>正确实现的Type 现在您需要一种构建实例的方法。 如果你可以确保你有一个无参数的构造函数,你可以调用Activator.CreateInstance(myGenericType) 这会给你一个RandomClass的实例,装在object中。

为了使用它,您需要以某种方式强制转换它,可能是GenericClass<RandomArgs>

如果您没有无参数构造函数,并且可以,请尝试使用 IoC 容器来为您发现构造函数依赖项进行艰苦的工作。 同样, Autofac是一个不错的候选者,但有很多选择,这是一个很深的兔子洞。

所以,在最简单的情况下,你只需要这样的东西:


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

我决定 go 另一条路线:

我已将我的ArgsBaseClass更新为以下内容:

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

现在,每当我创建此 class 的新实现时,我都被迫执行以下操作:

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

然后我的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