是否有可能需要开放的通用接口的通用约束?

sko*_*ima 5 c# generics type-inference

我正在实现一个存储库,并且一直在想使它对用户更友好。现在,我有一个IEntity指定Id字段的接口:

public interface IEntity<T>
{
    T Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的存储库允许用户通过该ID获取新实例。现在它可以处理的类型需要实现IEntity接口,因此我对存储库Get方法有一个通用约束:

public class Repository
{
    public T Get<T, U>(U id) where T: IEntity<U>
    {
        // fake implementation, but T is required at compile time
        var result = Activator.CreateInstance<T>();
        result.Id = id;
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

T和之间存在一个明显的关系,U并且编译器充分理解它可以标记未使用情况,但不足以启用类型推断-每次调用都Get需要显式指定泛型参数。我知道没有办法指定T,但是如何改善方法签名,以便U不需要指定呢?现在,对于最常见的用法,我有一个重载:

public T Get<T>(int id) where T : IEntity<int>
{
    return Get<T, int>(id);
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以通过某种方式将开放的通用接口指定为约束,或者对于一般情况,哪种方法更好?

sko*_*ima 4

阅读完C# 中可能的部分泛型类型推断后?解决缺乏带有约束的部分泛型类型推断的问题,我认为 Marc Gravell 的解决方案是最接近任何合理的解决方案。通过辅助类(用于捕获第一个参数的类型)和 Grax 建议的扩展方法推断来获取他的部分泛型参数应用程序,我最终得到了一个Repository实现

public class Repository
{
    public T Get<T, TId>(TId id) where T: IEntity<TId>
    {
        // fake implementation, but T is required at compile time
        var result = Activator.CreateInstance<T>();
        result.Id = id;
        return result;
    }

    public GetHelper<T> Get<T>()
    {
        return new GetHelper<T>(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

有帮手

public struct GetHelper<T>
{
    internal readonly Repository Repository;

    public GetHelper(Repository repository)
    {
        Repository = repository;
    }
}

public static class RepositoryExtensions
{
    public static T ById<T, TId>(this GetHelper<T> helper, TId id)
      where T : IEntity<TId>
    {
        return helper.Repository.Get<T, TId>(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

var intEntity = repository.Get<IntEntity>().ById(19);
var guidEndtity = repository.Get<GuidEntity>().ById(Guid.Empty);
Run Code Online (Sandbox Code Playgroud)

据我目前了解 C# 中泛型参数推断的工作原理,不可能获得部分推断。