通用类型问题的推论

Ras*_*par 6 c# generics types inference

我想这更像是一个公开咆哮,但为什么我不能用c#来推断我的Id类型?

public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
Run Code Online (Sandbox Code Playgroud)

和Guid作为Id的已定义EntityObject如下:

public Foo : EntityObject<Guid>
Run Code Online (Sandbox Code Playgroud)

继承自如下定义的抽象EntityObject类:

public abstract class EntityObject<IdT>
{
    public IdT id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

get方法的用法如下:

IRepository repository = new Repository();
var hydratedFoo = repository.Get<Foo>(someGuidId);
Run Code Online (Sandbox Code Playgroud)

编辑以提供进一步的说明.

Jon*_*eet 3

鉴于您只给出了两个声明,而不是如何使用它们,所以很难说。IdT 是另一个类型参数吗?(如果是TId,那就表明它是 - 但事实上,您正在使用EntityT另一个类型参数,这与约定相反,表明也许IdT也是......)

现在,假设IdT实际上是Guid在你的情况下,编译器应该如何计算出你的意思Foo?可能还有其他类型派生自EntityObject<Guid>.

简而言之,您没有向我们提供足够的信息来确定任何事情,但听起来您基本上对编译器提出了不合理的要求。

编辑:好的,这是我使用正常命名约定对您所拥有的内容的猜测:

public interface IRepository
{
    TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>
}

public abstract class EntityObject<TId>
{
    public IdT id { get; set; }
}

public class Foo : EntityObject<Guid> {} 
Run Code Online (Sandbox Code Playgroud)

你想做:

IRepository repository = GetRepositoryFromSomewhere();
Foo foo = repository.Get<Foo>(someGuid);
Run Code Online (Sandbox Code Playgroud)

而目前你必须做:

Foo foo = repository.Get<Foo, Guid>(someGuid);
Run Code Online (Sandbox Code Playgroud)

是的,编译器使您的工作变得比必要的更加困难。总共 6 个额外字符,是为了让语言更简单,类型推断的规则更容易理解。

基本上,类型推断是一件全有或全无的事情——要么推断出所有类型参数,要么推断出其中一个。这使得事情变得简单,因为您不需要弄清楚哪些是被指定的,哪些是没有指定的。这是问题的一部分,另一部分是你只能表达对方法的类型参数的约束 - 你不能:

class Repository<TEntity>
{
    TEntity Get<TId>(TId id) where TEntity : EntityObject<TId>
}
Run Code Online (Sandbox Code Playgroud)

因为那是限制TEntity,而不是TId。同样,这种事情使类型推断变得更简单。

现在你可以写:

Foo foo = repository.Get(someGuid).For<Foo>();
Run Code Online (Sandbox Code Playgroud)

使用适当的Get方法和额外的接口。我想我个人更喜欢直接使用Get<Foo, Guid>