Вопрос

Полагаю, это скорее публичная напыщенная речь, но почему я не могу заставить 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);

отредактировано для предоставления дополнительных разъяснений.

Это было полезно?

Решение

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

Другие советы

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

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

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

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

Но это, вероятно, не то, чего вам хотелось бы.

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

Если ваша сигнатура метода выглядела так:

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

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

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

РЕДАКТИРОВАТЬ (я ошибался): Продукт р = Получить (идентификатор);

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top