Вывод из общего вопроса типа - PullRequest
6 голосов
/ 11 августа 2009

Полагаю, это скорее общедоступный трюк, но почему я не могу заставить c # определить тип моего идентификатора?

public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>

и определенный объект EntityObject с идентификатором Guid следующим образом:

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

отредактировано для уточнения.

Ответы [ 4 ]

3 голосов
/ 11 августа 2009

Трудно сказать, учитывая, что вы дали только две декларации, а не то, как вы их используете. 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>.

0 голосов
/ 11 августа 2009

Вот почему я почти отказался от универсальных типов ключей с универсальными сущностями. Я не мог понять, как заставить мои сущности иметь общие типы ключей, не разбрасывая их повсюду. Теперь я остановился на целочисленных ключах (это то, что у меня есть везде), но это неправильно.

0 голосов
/ 11 августа 2009

декларация типа

public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>

требует, чтобы IdT был конкретным типом. Если вы также хотите параметризовать IdT, вам нужно использовать

public EntityT Get<EntityT, IdT>(IdT id) where EntityT : EntityObject<IdT>

Но это, вероятно, не то, что вы хотели бы.

0 голосов
/ 11 августа 2009

Если подпись вашего метода выглядела так:

public TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>

Компилятору будет с чем работать ...

Затем вы вызываете get с чем-то вроде:

РЕДАКТИРОВАТЬ (я был не прав): Продукт p = Получить (id);

Product p = Get<Product, Guid>(id);

Джон прибил этот ответ своим постом вверху, так что я замолчу и заползу обратно в свою дыру.

...