在C#中,我可以使用基于所使用的类型(T)的泛型的特定实现

时间:2016-03-21 20:16:29

标签: c# generics inheritance

我正在尝试在WPF / MVVM / Entity Framework中创建尽可能通用的类结构。我正在使用Prism&统一。真的,虽然我不认为任何重要的事情,除非我能在解决方案中使用Prism / Unity。

我有一个设置完美的系统,直到我需要运行特定于Type(T)的代码。

我真正想要的是,如果类型T具有匹配的派生类,系统将使用类的非泛型版本,否则我希望它使用通用版本。

在一个超级淡化的例子中,我有一个基类:

public class BaseClass<T>
{
    public T MyObject;

    protected virtual int GetErrorCount()
    {
        int errorCount = 0;

        if (MyObject == null)
            errorCount++;

        return errorCount;
    }
}

一个子类:

public class StringClass : BaseClass<String>
{
    protected override int GetErrorCount()
    {
        int errorCount = base.GetErrorCount();

        if (MyObject != null && MyObject.Length < 5)
            errorCount++;

        return errorCount;
    }
}

实施类:

public class ImplementationClass<T>
{
    public BaseClass<T> MyBaseObject;

    public ImplementationClass()
    {
        // If T is a string I want to use StringClass instead of the base
        // And it should happen automagically
        MyBaseObject = new BaseClass<T>();
    }
}

我有一些想法可以解决这个问题,包括复杂的开关或者在POCO类中抛出逻辑(逻辑数据),但这不是我想做的。

我已经抛弃了使用Dictionary和一些查找类的想法,每当我需要解析实际类型时都会使用它 - 但实际上是Prism所做的,所以我认为我可以用某种方式...只是可以弄明白了。

关于如何尽可能完成此任务的任何想法?

知道了吗,对此有何反馈?我需要注意什么?

解决方案(允许更改MyBaseObject):

public static class HelperExt
{
    internal static IEnumerable<Type> GetInhiritingTypes(this Type fatherT)
    {
        return fatherT.Assembly.GetTypes().Where(t => t.IsSubclassOf(fatherT) && !t.IsAbstract);
    }
}

public class ImplementationClass<T>
{
    private BaseClass<T> _myBaseObject;
    public BaseClass<T> MyBaseObject
    {
        get { return _myBaseObject; }
        set
        {
            Type instType = typeof(BaseDataViewModel<T>).GetInhiritingTypes().FirstOrDefault(t => t.BaseType.GetGenericArguments().Contains(typeof(T)));
            if (instType != null)
                SetProperty(ref _myBaseObject, (BaseClass<T>)Activator.CreateInstance(instType));
            else
                SetProperty(ref _myBaseObject, value);
        }
    }

    public ImplementationClass()
    {
        // If T is a string I want to use StringClass instead of the base
        // And it should happen automagically
        MyBaseObject = new BaseClass<T>();
    }
}

1 个答案:

答案 0 :(得分:1)

你可以通过一些反思来做到这一点,首先是这个辅助函数:

public static IEnumerable<Type> GetInhiritingTypes(this Type fatherT)
    {
        return fatherT.Assembly.GetTypes().Where(t => t.IsSubclassOf(fatherT) && !t.IsAbstract);
    }

然后:

Type genericType = typeof(string);
Type typeToInstantiate = typeof(BaseClass<String>).GetInheritingTypes().FirstOrDefault(t=>t.GetGenericsArguments().Contains(genericType));
if (typeToInstantiate != null)
    MyBaseObject = (BaseClass<T>)Activator.CreateInstance(typeToInstantiate);
else
    MyBaseObject = new BaseClass<T>();

但是安全性非常低&#34;在使用这样的方法。您也可以编写一个带有类名的工厂函数,并实例化该类的实例。