2009-08-11 3 views
6

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

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

Использование метода Доберутся должны быть следующими:

IRepository repository = new Repository(); 
var hydratedFoo = repository.Get<Foo>(someGuidId); 

отредактирован для уточнения подробностей.

ответ

3

Трудно сказать, учитывая, что вы указали только два объявления, а не то, как вы их используете. Является ли IdT другим параметром типа где-нибудь? (Если бы это было TId, что хотел бы предложить это - но тот факт, что вы используете EntityT для другого параметра типа, в отличие от конвенций, свидетельствует о том, что может быть IdT как хорошо ...)

Теперь, предполагая, что IdT является на самом деле Guid в вашем случае, как должен компилятор работать, что вы имеете в виду Foo? Могут быть другие типы, происходящие от EntityObject<Guid>.

Короче говоря, вы не дали нам достаточно информации, чтобы что-то сказать наверняка, но похоже, что вы в основном делаете необоснованные требования к компилятору.

EDIT: Хорошо, вот моя догадка, что у вас есть, используя обычные правила именования:

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>.

+1

Jon, Извините, что не добавлял больше деталей. Опять же, это было больше, чем вопрос манжеты, а не действительно законный вопрос. Но imho компилятор должен иметь возможность определять IdT из объекта foo во время компиляции. Скорее всего, это мои предположения для дженериков, которые приводят меня к ошибочной интерпретации того, как компилятор мог/должен был прочитать это, но я предположил, что общий тип не был определен до момента компиляции, после чего компилятор затем связал шаблонный объект. Предполагая, что, не было бы еще одним шагом определить тип ссылочного объекта? – Raspar

+0

Generics! = Шаблоны. Вероятно, вы могли бы заставить компилятор C++ «вывести» что-то вроде этого, но до тех пор, пока генерики не исполняются, я не вижу, чтобы это происходило без более четкого общего определения. – user7116

+0

IdT не является параметром типа 'Get', который имеет только один параметр типа' EntityT'. Вы не дали объявление IRepository, или то, что не работает для вас. Пожалуйста, дайте * полный * пример, показывающий, что вы * пытаетесь * сделать и рассказываете нам, что происходит, а не то, что вы хотите. –

0

Если подпись метода выглядит следующим образом:

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

компилятор будет иметь что-то, чтобы работать с ...

Затем вызывается получить что-то вроде:

EDIT (я был неверно): Продукт p = Get (id);

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

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

+0

Это, безусловно, работает, но делает его болезненно очевидным для всех, что ключ Foo - это Guid. – n8wrl

+0

@ n8wrl Я не понимаю вашего комментария. – grenade

+0

True Rob, я ценю ваш ответ, однако Repository.Get (someGuid) потребует от разработчика знать тип идентификатора каждого объекта.Также ему не хватало синтаксической сладости, которую имел бы Repository.Get (someGuid). – Raspar

0

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

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

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

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

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

0

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

+0

Точно! В настоящее время мы используем Guids, но теперь, когда нам нужно включить устаревшую базу данных, мы теперь имеем дело с идеей составного идентификатора. Тьфу. – Raspar

+0

Вы хотите найти тип вывода. При вызове общего метода вам не нужно быть явным. – grenade

+0

@Rob: Ну, иногда вы этого не делаете, а иногда и делаете. Это зависит от конкретной ситуации. –