我正在实施一个存储库,并一直想知道如何让它对用户更友好一些。现在我有一个IEntity
接口,指定Id
字段:
public interface IEntity<T>
{
T Id { get; set; }
}
我的存储库允许用户通过该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;
}
}
T
和U
之间存在明显的关系,编译器很好地理解了错误用法,但还不足以启用类型推断 - 每次调用Get
都需要指定通用参数明确。我知道无法指定T
,但如何改进方法签名以便不需要指定U
?现在我有一个最常用的过载:
public T Get<T>(int id) where T : IEntity<int>
{
return Get<T, int>(id);
}
我想知道是否有可能以某种方式指定一个开放的通用接口作为约束,或者对于一般情况更好的方法签名。
答案 0 :(得分:2)
您可以使用扩展方法做些有趣的事情。
public static class Extensions
{
public static T Get<T>()
{
// fake implementation, but T is required at compile time
var result = Activator.CreateInstance<T>();
return result;
}
public static T AssignId<T, U>(this T entity, U id)
where T : IEntity<U>
{
entity.Id = id;
return entity;
}
}
这将被称为如下。
var result = Extensions.Get<EntityInt>().AssignId(34);
var result2 = Extensions.Get<EntityString>().AssignId("WALKEN");
您可以将get方法放在任何您喜欢的位置,但AssignId方法必须位于有资格拥有扩展方法的类中,即它必须是静态非泛型类,并且您可能需要一个引用的using语句到包含扩展方法的命名空间。
答案 1 :(得分:2)
在阅读Partial generic type inference possible in C#?和Working around lack of partial generic type inference with constraints之后,我认为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);
}
}
带帮助者
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);
}
}
然后用法如下:
var intEntity = repository.Get<IntEntity>().ById(19);
var guidEndtity = repository.Get<GuidEntity>().ById(Guid.Empty);
据我所知,泛型参数推断现在如何在C#中起作用,因此无法进行部分推理。