【问题标题】:Working around lack of partial generic type inference with constraints解决缺乏带有约束的部分泛型类型推断的问题
【发布时间】:2013-05-10 09:55:48
【问题描述】:

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

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

这允许调用者指定实体类型 (T) 及其类型为 Id 字段 (TId)。然后,该接口的实现者会找到 T 类型的实体,并使用 id 参数根据它们的 id(在 IEntity&lt;TId&gt; 上定义)过滤它们。

目前我这样称呼它:

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&lt;T,TId&gt;(TId)'. There is no implicit reference conversion from 'T' to 'PartsLegislation.Repository.IEntity&lt;TId&gt;'.

我明白它在说什么,因为我的包装类中的 T 仅被限制为引用类型,但 FindById 函数希望它是 IEntity&lt;TId&gt;,但我不能这样做,因为 @ 987654336@ 在方法中(否则我会回到第一方)。

我怎样才能解决这个问题(或者我不能)?

【问题讨论】:

  • 您不能将TID 作为约束添加到FindIdWrapper 吗?
  • @Nick 不,因为 TID 在部分应用时是未知的

标签: c# generics type-inference


【解决方案1】:

这不能正常工作,因为事后您无法说服编译器 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);
    }
}

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

【讨论】:

  • 我只是在我的回答中写了同样的内容。马克你太快了!我在我的代码中使用了相同的方法,我也希望我能写出更优雅的东西..
  • 太好了,谢谢!老实说,一旦我意识到我无法进行部分泛型类型推断,那主要是学术性的。 :)
  • 我有稍微不同的名字让它“更好”:Lookup(id).From&lt;Customers&gt;().
猜你喜欢
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多