使用约束来解决缺少部分泛型类型推断的问题

时间:2013-05-10 09:55:49

标签: c# generics type-inference

我有一个具有此成员的接口(由存储库使用):

T FindById<T, TId>(TId id)
    where T : class, IEntity<TId>
    where TId : IEquatable<TId>;

这允许调用者指定实体类型(T)及其Id字段(TId)的类型。然后,此接口的实现者将查找T类型的实体,并使用id参数根据其id(在IEntity<TId>上定义)对其进行过滤。

目前我这样称呼它:

int id = 123;
var myApproval = PartsDC.FindById<Approval, int>(id);

理想情况下,我想这样做:

int id = 123;
var myApproval = PartsDC.FindById<Approval>(id);

我已经阅读了这个问题的答案:

Partial generic type inference possible in C#?

我知道我无法获得我想要的语法,但可以接近。由于我的通用参数约束,我无法在我的情况下完全设置它。

这是我到目前为止所拥有的:

public class FindIdWrapper<T> where T : class
{
    public readonly IDataContext InvokeOn;

    public FindIdWrapper(IDataContext invokeOn)
    {
        InvokeOn = invokeOn;
    }

    T ById<TId>(TId id) where TId : IEquatable<TId>
    {
        return InvokeOn.FindById<T, TId>(id);
    }
}

public static class DataContextExtensions
{
    public static FindIdWrapper<T> Find<T>(this IDataContext dataContext) where T : class, IEntity
    {
        return new FindIdWrapper<T>(dataContext);
    }
}

我得到的编译错误是:

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'PartsLegislation.Repository.IDataContext.FindById<T,TId>(TId)'. There is no implicit reference conversion from 'T' to 'PartsLegislation.Repository.IEntity<TId>'.

我理解它的含义是因为我的包装器类中的T仅限制为引用类型,但FindById函数希望它为IEntity<TId>,但我可以'这样做是因为TId在方法中(否则我回到正方形)。

我如何解决这个问题(或者我不能)?

1 个答案:

答案 0 :(得分:4)

这不能正常工作,因为你不能在事后说服编译器TId约束。但是,您可以颠倒顺序,即

var obj = ById(id).Find<SomeType>();

不那么优雅,但它有效。实现:

public Finder<TId> ById<TId>(TId id) where TId : IEquatable<TId>
{
    return new Finder<TId>(this, id);
}
public struct Finder<TId> where TId : IEquatable<TId>
{
    private readonly YourParent parent;
    private readonly TId id;
    internal Finder(YourParent parent, TId id)
    {
        this.id = id;
        this.parent = parent;
    }
    public T Find<T>() where T : class, IEntity<TId>
    {
        return parent.FindById<T, TId>(id);
    }
}

警告:明确告诉它两种参数类型可能更容易。