从泛型问题推断
Posted
技术标签:
【中文标题】从泛型问题推断【英文标题】:Inference from Generic Type Question 【发布时间】:2010-11-18 17:04:13 【问题描述】:我想这更像是一个公开的咆哮,但为什么我不能让 c# 推断我的 Id 的类型?
public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
和一个定义的 EntityObject 与一个 Guid 作为一个 Id 如下:
public Foo : EntityObject<Guid>
继承自抽象EntityObject类定义如下:
public abstract class EntityObject<IdT>
public IdT id get; set;
get 方法的用法如下:
IRepository repository = new Repository();
var hydratedFoo = repository.Get<Foo>(someGuidId);
已编辑以提供进一步的说明。
【问题讨论】:
【参考方案1】:很难说你只给出了两个声明,而不是你如何使用它们。 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>
你想做的:
IRepository repository = GetRepositoryFromSomewhere();
Foo foo = repository.Get<Foo>(someGuid);
而目前你必须这样做:
Foo foo = repository.Get<Foo, Guid>(someGuid);
是的,编译器让你稍微变得比必要的更难。整整 6 个额外字符,以使语言更简单,类型推断规则更易于理解。
基本上,类型推断是全有或全无的事情——所有类型参数都被推断出来,或者它们都不被推断出来。这使它变得简单,因为您不需要确定哪些是指定的,哪些不是。这是问题的一部分,另一部分是你只能表达对方法的类型参数的约束——你不能:
class Repository<TEntity>
TEntity Get<TId>(TId id) where TEntity : EntityObject<TId>
因为这是限制TEntity
,而不是TId
。同样,这类事情使类型推断更简单。
现在你可以写:
Foo foo = repository.Get(someGuid).For<Foo>();
使用适当的Get
方法和额外的接口。我想我个人更喜欢使用Get<Foo, Guid>
。
【讨论】:
乔恩,我很抱歉没有添加更多细节。同样,这是一个更即兴的咆哮,而不是一个真正合理的问题。但是恕我直言,编译器应该能够在编译时从 foo 对象中确定 IdT。很可能是我对泛型的假设导致我对编译器可以/应该如何读取它的解释有缺陷,但我认为泛型类型直到编译时才确定,此时编译器将链接模板化对象.假设,确定被引用对象的类型不是更进一步吗? 泛型 != 模板。您可能可以让 C++ 编译器“推断”这类事情,但只要泛型是运行时的,如果没有更明确的泛型定义,我就不会看到它发生。 IdT 不是Get
的类型参数——它只有一个类型参数EntityT
。你还没有给出 IRepository 的声明,或者什么对你不起作用。请给出一个完整的示例,展示您尝试做什么,并告诉我们会发生什么而不是您想要什么。
我更喜欢使用 public class RepositoryBase类似的声明
public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
要求 IdT 是一种具体类型。如果您还想参数化 IdT,则需要使用
public EntityT Get<EntityT, IdT>(IdT id) where EntityT : EntityObject<IdT>
但这可能不是你想要的。
【讨论】:
【参考方案3】:这就是为什么我几乎放弃了具有通用实体的通用键类型。我无法弄清楚如何让我的实体拥有通用键类型,而不会将这两种类型洒在整个地方。现在我已经确定了整数键(反正我到处都有),但感觉不对。
【讨论】:
没错!目前我们一直在使用 Guid,但现在我们需要合并一个遗留数据库,我们现在正在处理复合 ID 的想法。糟糕。 你想发现类型推断。调用泛型方法时不需要显式。 @Rob:嗯,有时你不会,有时你会。这取决于具体情况。【参考方案4】:如果您的方法签名如下所示:
public TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>
编译器可以使用一些东西...
然后你调用 get 类似的东西:
编辑(我错了):Product p = Get(id);
Product p = Get<Product, Guid>(id);
Jon 用他的帖子顶了这个答案,所以我会闭嘴并爬回我的洞里。
【讨论】:
这确实有效,但让每个人都痛苦地意识到 Foo 的密钥是一个 Guid。 @n8wrl 我不明白你的评论。 True Rob,感谢您的回答,但是 Repository.Get以上是关于从泛型问题推断的主要内容,如果未能解决你的问题,请参考以下文章