public class BaseEntity
{
}
public class Entity1 : BaseEntity
{
}
public class Entity2 : BaseEntity
{
}
public interface IBaseModel<T> where T : BaseEntity
{
}
public class Model1 : IBaseModel<Entity1>
{
}
public class Model2 : IBaseModel<Entity2>
{
}
Нужна фабрика, которая бы в зависимости от входного параметра, создавала бы нужный экземпляр Model1, Model2 без приведения типов...
Здравствуйте, white_znake, Вы писали:
_>Нужна фабрика, которая бы в зависимости от входного параметра, создавала бы нужный экземпляр Model1, Model2 без приведения типов...
Что значит без приведения типов?
У Model1 и Model2 ближайший общий предок — System.Object. Метод, который может вернуть и Model1 и Model2 должен возвращать System.Object.
Здравствуйте, white_znake, Вы писали:
_>Нужна фабрика, которая бы в зависимости от входного параметра, создавала бы нужный экземпляр Model1, Model2 без приведения типов...
Рассказывайте, что не устраивает в следующем методе и будем исправлять.
public object CreateModel(object parameter) {
if(IsNeedModel1(parameter)) {
return new Model1();
} else if(IsNeedModel2(parameter)) {
return new Model2();
}//ifreturn null;
}
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, samius, Вы писали:
S>Что значит без приведения типов? S>У Model1 и Model2 ближайший общий предок — System.Object. Метод, который может вернуть и Model1 и Model2 должен возвращать System.Object.
На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
А еще можно представить дженерик-фабрику, тип производимой модели для которой будет определятся в (jit)компайл-тайм. И тоже без приведений моделей к общему типу.
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Klapaucius, Вы писали:
S>>Что значит без приведения типов? S>>У Model1 и Model2 ближайший общий предок — System.Object. Метод, который может вернуть и Model1 и Model2 должен возвращать System.Object.
K>На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
Ага, а вот как использовать-то это добро? такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
K>А еще можно представить дженерик-фабрику, тип производимой модели для которой будет определятся в (jit)компайл-тайм.
Что значат скобочки вокруг (jit)?
K>И тоже без приведений моделей к общему типу.
И как с такими моделями работать? И как оно будет выглядеть в шарпе (интерфейс хотя бы)?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Klapaucius, Вы писали:
K>>На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
_FR>Ага, а вот как использовать-то это добро? такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
Either позволит формально обойтись без приведения/проверки типа.
Здравствуйте, Klapaucius, Вы писали:
K>Здравствуйте, samius, Вы писали:
K>На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
По поводу суммы/Either согласен, но это уже не характерно для .NET-а.
K>А еще можно представить дженерик-фабрику, тип производимой модели для которой будет определятся в (jit)компайл-тайм. И тоже без приведений моделей к общему типу.
Здравствуйте, _FRED_, Вы писали:
_FR>такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
Одно принципиальное отличие я, в общем-то, уже называл. Either — закрытый, так что там может быть (например) или Model1 или Model2, а под маской object-а может быть что угодно. Но есть и еще отличия. Either мог бы быть сделан так, чтобы было невозможно получить Model1 без предварительной проверки, что он там есть. А object можно просто даункастить к Model1 — писать проверку is Model1 никто не заставляет. Но не в шарпе, конечно, кастить Either к Left<Model2> не запретишь.
_FR>Что значат скобочки вокруг (jit)?
Ничего особенного. Это просто примечание, что под компайл-таймом имеется в виду компиляция джитом, а не в байт-код.
_FR>И как с такими моделями работать? И как оно будет выглядеть в шарпе (интерфейс хотя бы)?
//фабрика ничего не знает про IAnotherModelMethodpublic delegate TM ModelFactory<out TM, in TE>(TE entity)
where TM : IBaseModel<TE>
where TE : BaseEntity;
public class FactoryUser
{
public static void UseEntity<TM, TE>(ModelFactory<TM, TE> factory, TE entity)
where TM : IBaseModel<TE>, IAnotherModelMethod //a UseEntity знаетwhere TE : BaseEntity
{
var model = factory(DoSomething(entity));
model.Foo(); //метод IBaseModel
model.BlahBlahBlah(); //метод IAnotherModelMethod
}
}
//где-то в другой сборке:
FactoryUser.UseEntity(e => new Model1(DoSomething(e)), new Entity1());
Я, кстати, не стану спорить, если кто-то скажет, что все это проходит по разряду извращений: шарп — явно не тот язык, на котором можно многое написать не прибегая к даункастам. Придется продираться через тернии угловых скобочек пока не обнаружится, что путь к звездам перегорожен отсутствием higher-kinded полиморфизма или еще чем-нибудь. Так что возвращать object из фабрики и кастить — это вполне нормальный С#-way.
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, samius, Вы писали:
K>>>На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
_FR>>Ага, а вот как использовать-то это добро? такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
S>Either позволит формально обойтись без приведения/проверки типа.
А этого можно добиться очень многими способами. Функционально-то что было, то и есть: результат нужно проверить, а потом применить некую функцию от результата, что бы добраться до самой модели.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Klapaucius, Вы писали:
_FR>>такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
K>Одно принципиальное отличие я, в общем-то, уже называл. Either — закрытый, так что там может быть (например) или Model1 или Model2, а под маской object-а может быть что угодно.
"Закрытость" object-а здесь гарантирует реализация фабрики. И в том object-е может быть ровно то же, что и в Either-е, то есть в данном случае существует взаимно-однозгначное преобразование object->Either. Но преимущества для пользователя никакого не будет — он как не мог ничего вызывать от результата работы фабрики, так и не может, а вот узнать что именно вернулось может в любом слачае.
K>Но есть и еще отличия. Either мог бы быть сделан так, чтобы было невозможно получить Model1 без предварительной проверки, что он там есть. А object можно просто даункастить к Model1 — писать проверку is Model1 никто не заставляет. Но не в шарпе, конечно, кастить Either к Left<Model2> не запретишь.
А даункаст это разве не та же проверка? Если цимес в том, что "не та же" всмысле более контролируема, то в данном случае топикстартеру от этого ни тепло ни холодно. Наоборот: имея object он сможет передать его, например, куда-то для биндинга/сериализации или чего-ещё, а вот над either-он надо ещё будет для этого потрясти бубном.
_FR>>И как с такими моделями работать? И как оно будет выглядеть в шарпе (интерфейс хотя бы)?
K>//фабрика ничего не знает про IAnotherModelMethod
K>public delegate TM ModelFactory<out TM, in TE>(TE entity)
K> where TM : IBaseModel<TE>
K> where TE : BaseEntity;
Это уже совсем "не фабрика" в контексте топика, где требуется создать объект в зависимости от.
K>Я, кстати, не стану спорить, если кто-то скажет, что все это проходит по разряду извращений: шарп — явно не тот язык, на котором можно многое написать не прибегая к даункастам.
Да нет, довольно много можно. Проблема в том, что из-за BCL/FCL часто без даункастов никак. С хорошим фреймворком можно свести даункасты к минимуму.
K>Придется продираться через тернии угловых скобочек пока не обнаружится, что путь к звездам перегорожен отсутствием higher-kinded полиморфизма или еще чем-нибудь. Так что возвращать object из фабрики и кастить — это вполне нормальный С#-way.
Нет, нормальный way — это описание нормального (для [скромных] возможностей шарпа) интерфейса модели. В данном примере топикстартер просто поленился показать то, каким образом он собирается (или ему хотелось бы) использовать свои энтити и модели — в таком разрезе ничего конкретного посоветовать нельзя.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, samius, Вы писали:
K>>>>На самом деле не должен, конечно. Он может возвращать тип сумму Model1 + Model2. Т.е. Either<Model1,Model2>. И можно представить себе фабрику, которая возвращает сумму моделей, принимая параметром сумму энтити, например. Понятно, что множество наследников открыто, а сумма закрыта, ну так это может даже быть полезным.
_FR>>>Ага, а вот как использовать-то это добро? такой Either по сути ничем не будет от object-а отличаться, достаточно Either::IsFirst заменить на is Model1
S>>Either позволит формально обойтись без приведения/проверки типа.
Вот тут я лопухнул. Смутило меня Either::IsFirst. Если плясать от хаскеля, то соответствующая C#-у конструкция будет выглядеть как ... is Left.
_FR>А этого можно добиться очень многими способами. Функционально-то что было, то и есть: результат нужно проверить, а потом применить некую функцию от результата, что бы добраться до самой модели.
Да, можно взять Tuple<Model1, Model2> и проверять его компоненты на null.
Здравствуйте, _FRED_, Вы писали:
_FR>Нет, нормальный way — это описание нормального (для [скромных] возможностей шарпа) интерфейса модели. В данном примере топикстартер просто поленился показать то, каким образом он собирается (или ему хотелось бы) использовать свои энтити и модели — в таком разрезе ничего конкретного посоветовать нельзя.
Действительно, если нет хоть какого-то полиморфного поведения, смысла засовывать разнотипные объекты в одну фабрику не много.
Здравствуйте, _FRED_, Вы писали:
_FR>"Закрытость" object-а здесь гарантирует реализация фабрики.
Даже если фабрика конкретная — о каких-то гарантиях говорить сложно — они ведь явно в виде интерфейса не выражены. Если же фабрика абстрактна — тут все "гарантии" и вовсе вилами по воде писаны.
_FR>И в том object-е может быть ровно то же, что и в Either-е, то есть в данном случае существует взаимно-однозгначное преобразование object->Either. Но преимущества для пользователя никакого не будет — он как не мог ничего вызывать от результата работы фабрики, так и не может, а вот узнать что именно вернулось может в любом слачае.
У пользователя одинаковые возможности для того, чтобы определить вернулось ли то, что он ожидает. Но что он может ожидать от object? Да чего угодно. Если в случае суммы типов — все возможные возвращаемые модели в интерфейсе перечислены, то какая есть возможность узнать, что возвращает фабрика в обджекте? Посмотреть ее исходный код? Испытать на всех возможных входных данных? Все-таки тип — это автоматически проверяемая и всегда актуальная документация.
_FR>имея object он сможет передать его, например, куда-то для биндинга/сериализации или чего-ещё, а вот над either-он надо ещё будет для этого потрясти бубном.
Это, конечно, верно. Either, правда, может иметь преобразование к object.
_FR>Это уже совсем "не фабрика" в контексте топика, где требуется создать объект в зависимости от.
Требовалось создавать объект определенного типа в зависимости от параметра. В данном случае — в зависимости от параметра типа. Это просто вторая попытка домысливания вопроса до того, чтобы в нем появился хоть какой-то смысл.
_FR>Да нет, довольно много можно. Проблема в том, что из-за BCL/FCL часто без даункастов никак. С хорошим фреймворком можно свести даункасты к минимуму.
Полагаю, что BCL/FCL такая не от хорошей жизни. Конечно, там могут быть неоправданно плохие решения, но по большому счету проблемы библиотеки — прямое следствие недостатков в системе типов CLR. Проблема в том, что фактически из триады (полиморфный код, иммутабельные объекты, отсутствие даункастов) можно выбрать только два пункта. При чем тут иммутабельность объектов? Ну, у них много "замкнутых" операций. Отображающих из множества объектов в то же множество. Тут мы впервые сталкиваемся с потерей информации о типах, которое я описал здесь
. Там же написано как это обходить (с дополнительными проблемами в виде нагромождения параметров типов, "загрязнения" простаранства имен и списка автодополнения, а также проблем с выведением параметров типов, но для части из этих проблем тоже есть решения), но обходится это до поры, пока не понадобятся операции вроде Select, которые из типа C<T> делают тип C<V>. Все, тут без даункастов уже не обойтись, потому как higher-kinded полиморфизм отсутствует. Да и ко/контравариантность для классов потом понадобится, а не только для интерфейсов и делегатов. В BCL/FCL проблема работы с коллекциями без их изменения по месту еще относительно удачно решена — там есть итераторы-монады (ну и функторы, понятное дело), которые комбинируются, а потом из них какой-нибудь ToList или ToDictionary строит окончательную, нужную нам, структуру данных. Но итераторы имеют только минимальный набор операций, информации о типе источника не имеют, так что на практике полиморфный код дается ценой ухудшения асимптотики алгоритмов в ряде случаев. Поэтому в абстракциях проиходится все теми же даункастами пробивать дыры. За примерами далеко ходить не надо, тот же Enumerable.Count содержит внутри хак:
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
return is2.Count;
}
Получается, что экстеншн для IEnumerable знает о существовании ICollection. Просто замечательно.
_FR>Нет, нормальный way — это описание нормального (для [скромных] возможностей шарпа) интерфейса модели.
Тут принципиальной разницы и нет — апкаст к интерфейсу или к object — это все один способ написания полиморфного кода и даункаст при таком подходе вполне штатное и широко используемое средство. Ну а то, что это падает в рантайме и плохо проверяется компилятором — ну так ООП вообще пришел из динамики. Там падение в рантайме — это и есть единственная возможная проверка.
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Проектирование...
От:
Аноним
Дата:
26.07.10 20:12
Оценка:
_>Нужна фабрика, которая бы в зависимости от входного параметра, создавала бы нужный экземпляр Model1, Model2 без приведения типов...
Взаимоисключающие требования: в зависимости от входного параметра — значит, динамически, без приведения типа — значит, статически.
Если ты не собираешься использовать dynamic, задача не имеет смысла.
Здравствуйте, Аноним, Вы писали:
_>>Нужна фабрика, которая бы в зависимости от входного параметра, создавала бы нужный экземпляр Model1, Model2 без приведения типов...
А>Взаимоисключающие требования: в зависимости от входного параметра — значит, динамически, без приведения типа — значит, статически.
Можно обойтись без приведений имея выходным результатом кортеж.