是否有可能有一个通用的约束需要一个开放的通用接口? [英] Is it possible to have a generic constraint requiring an open generic interface?

查看:102
本文介绍了是否有可能有一个通用的约束需要一个开放的通用接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实施一个存储库,并不断想知道如何让它对用户更加友好。现在我有一个 IEntity 接口,它指定了一个 Id 字段:

  public interface IEntity< T> 
{
T Id {get;组; }
}

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

  public class Repository 
{
public T Get< T,U>(U id)where T:IEntity< U>
{
//假实现,但是在编译时需要T
var result = Activator.CreateInstance< T>();
result.Id = id;
返回结果;


T 和 U ,编译器理解它足以标记未使用,但不足以启用类型推断 - 每次调用 Get 需要明确指定通用参数。我知道指定 T 没有办法,但我该如何改进方法签名,以便不需要指定 U ?现在我有一个最常见用法的重载:

  public T Get< T>(int id)其中T:IEntity< ; INT> 
{
return Get< T,int>(id);

$ / code>

我想知道是否有可能以某种方式指定一个开放的通用接口为一个约束或什么是一般情况下更好的方法签名。 解决方案

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

  public class Repository 
{
public T Get< T,TId>(TId id )其中T:IEntity< TId>
{
//假实现,但是在编译时需要T
var result = Activator.CreateInstance< T>();
result.Id = id;
返回结果;
}

public GetHelper< T> Get< T>()
{
return new GetHelper< T>(this);


$ / code $ / pre

带助手

  public struct GetHelper< T> 
{
内部只读版本库版本库;

public GetHelper(Repository repository)
{
Repository = repository;



public static class RepositoryExtensions
{
public static T ById< T,TId>(this GetHelper< T> helper,TId id )
其中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#中是如何工作的,不可能得到部分推断。

I'm implementing a repository and keep wondering about making it a bit more friendly to the user. Right now I have an IEntity interface that specifies an Id field:

public interface IEntity<T>
{
    T Id { get; set; }
}

And my repository allows users to get an new instance by that id. Now the types it can handle need to implement the IEntity interface, so I have a generic constraint on the repository Get method:

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;
    }
}

There's an obvious relation between T and U and compiler understands it well enough to flag miss-usages, but not enough to enable type inference - each call to Get requires specifying the generic parameters explicitly. I know there's no way around specifying T, but how can I improve the method signature so that specifying U is not required? Right now I have an overload for the most common usage:

public T Get<T>(int id) where T : IEntity<int>
{
    return Get<T, int>(id);
}

I'm wondering if it is possible to somehow specify an open generic interface as a constraint or what would be a better method signature for the general case.

解决方案

After reading Partial generic type inference possible in C#? and Working around lack of partial generic type inference with constraints, I'm thinking that Marc Gravell's solution is the closest to any reasonable. Taking his partial generic parameter application via a helper class (which is used to capture the type of the first parameter) and the extension method inference that Grax suggested, I end up with a Repository implementation of

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);
    }
}

with a helper

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);
    }
}

The usage then looks like that:

var intEntity = repository.Get<IntEntity>().ById(19);
var guidEndtity = repository.Get<GuidEntity>().ById(Guid.Empty);

As far as I understand how generic parameter inference works in C# right now, it's not possible to get a partial inference.

这篇关于是否有可能有一个通用的约束需要一个开放的通用接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆