Вывод из универсального вопроса о типе

Мы помещаем значения по умолчанию в базу данных посредством миграций (путем определения :default опция на каждом определении столбца) и позволяем Активному Рекордному использованию эти значения для установки значения по умолчанию для каждого атрибута.

, по моему скромному мнению, этот подход выровненный принципов AR: соглашение по конфигурации, DRY, определение таблицы управляет моделью, не наоборот.

Примечание, что значения по умолчанию находятся все еще в приложении (Ruby) код, хотя не в модели, а в миграции (миграциях).

6
задан Raspar 11 August 2009 в 18:05
поделиться

4 ответа

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

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

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

РЕДАКТИРОВАТЬ: Хорошо, вот ' я предполагаю, что у вас есть, используя обычные соглашения об именах:

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 .

3
ответ дан 17 December 2019 в 18:18
поделиться

Объявление типа

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

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

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

Но, вероятно, это не то, что вам нужно.

0
ответ дан 17 December 2019 в 18:18
поделиться

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

0
ответ дан 17 December 2019 в 18:18
поделиться

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

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

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

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

EDIT (я был неправильно): Product p = Get (id);

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

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

0
ответ дан 17 December 2019 в 18:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: