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)
我想知道是否可以通过某种方式将开放的通用接口指定为约束,或者对于一般情况,哪种方法更好?
阅读完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# 中泛型参数推断的工作原理,不可能获得部分推断。