C#:对子类型的泛型方法约束

时间:2018-05-30 07:39:44

标签: c# generics constraints

我有两种基类:

public class Parent { }
public abstract class Child : Parent 
{
    string ChildKey { get; set; }
}

来自家长,有很多孩子:

public class Kid1 : Parent { public string Name { get; set; } }
public class Kid2 : Parent { public long Number { get; set; } }
...

以及许多儿童作为特殊群体的具有额外属性的孩子:

public class Child1 : Child { public string Street { get; set; } }
public class Child2 : Child { public long Account { get; set; }}

现在我有两个通用的存储库类,其中“Special One”通过使用额外的过滤器对更多属性更具体:

public class Repository<T> : IRepository<T> where T : Parent 
{ 
    public IEnumerable<T> GetAll() { return something; }
}
public class ChildRepository<T> : Repository<T>, IChildrenRepository<T> where T : Child 
{ 
    public override IEnumerable<T> GetAll() { return base.GetAll().Where(x => x.ChildKey == "y"); }
}

使用接口:

public interface IRepository<T> where T : Parent
{ IEnumerable<T> GetAll(); }
public interface IChildRepository<T> : IRepository<T> where T : Child { }

我还需要GetAll()的类型安全性 - 结果。

现在我需要一个通用方法来创建所需的存储库:

IRepository<T> GetRepository() where T : WhatConstraint
{
    if (typeof(Child).IsAssignableFrom(T))
        return new ChildRepository<T>();    // return 1
    return new Repository<T>();             // return 2
}

正确的约束是什么? return 1需要Child-Constraint(返回2是错误的),说类型T不能用作方法中的类型参数,因为没有从T到Child的隐式引用转换。

T:Child-constraint在ChildRepository中更精确(因此我很有用,因为我可以依赖一些属性)。如果我使用相同的T:存储库的父约束,我必须输入 - 检查T是否始终从Child派生...

这有什么解决方案吗?

1 个答案:

答案 0 :(得分:0)

好的,这是一个详细的解决方案(可以写得更短,也更不易读)。由于Repository和ChildRepository存在冲突的约束(这对存储库有好处,但对GetRepository-factory不利),我无法使用new-keyword创建ChildRepository。我必须通过CreateInstance创建这个对象。

IRepository<T> GetRepository() where T : Parent
{
    if (typeof(Child).IsAssignableFrom(T))
    {
        Type childType = typeof(T);  // which is both, Parent and Child
        Type classType = typeof(ChildRepository<>);
        Type[] typeParams = { childType };
        Type repositoryType = classType.MakeGenericType(typeParams);
        return Activator.CreateInstance(resultType) as IRepository<T>;
    }
    return new Repository<T>();
}

此解决方案的缺点:更复杂的代码分析,不清楚结果的可空性,不是非常直观的可读性(尤其是现有的约束)。但它确实有效。