Привет.
Можно ли делать Events в виде дженериков? Суть в том что есть сообщение об изменении параметров, вот эти параметры могут быть различных типов.
Сделал вот так
public delegate void ParameterChangeDelegate<T>(MyEventArgs<T> e);
public event ParameterChangeDelegate<float> OnFloatParameterChange;
public event ParameterChangeDelegate<String> OnStringParameterChange;
public event ParameterChangeDelegate<Int32> OnIntParameterChange;
но так на каждый тип придется добавлять Event. Не хочется так
И еще.
Допустим есть класс, который хранит имя параметра и допустимые значения, что то типа такого
class Param<T>
{
String Name;
List<T> Values;
}
Хочу хранить эти параметры в List<Param>.
Что же теперь для хранения каждого параметра нужно заводить отдельный Param<int>, Param<String>?
Или можно сделать как нибудь по другому??
Здравствуйте, Аноним, Вы писали:
А>Привет. А>Можно ли делать Events в виде дженериков? Суть в том что есть сообщение об изменении параметров, вот эти параметры могут быть различных типов. А>Сделал вот так
А>но так на каждый тип придется добавлять Event. Не хочется так
Тогда альтернатива:
public event ParameterChangeDelegate<object> OnParameterChange
Кстати, обычно такие события именую как Changed или Changing, в зависимости от того, приходят они после фактического изменения значения (первый вариант) или перед изменением (часто, аргументы таких событий позволяют отменить грядущее изменение).
А>И еще. А>Допустим есть класс, который хранит имя параметра и допустимые значения, что то типа такого
А>Хочу хранить эти параметры в List<Param>. А>Что же теперь для хранения каждого параметра нужно заводить отдельный Param<int>, Param<String>? А>Или можно сделать как нибудь по другому??
Вариантов несколько. Основное — надо предоставить типонезависимый доступ к экземпляру Param. Например, так:
interface IParam
{
String Name { get; set; }
ReadOnlyCollection<object> Values { get; set; }
}
А>class Param<T> : IParam
А>{
private IList<T> values;
private ReadOnlyCollection<object> readOnlyValues;
А> String Name { get; set;} // сделаем эти члены свойствами, а не полями
А> List<T> Values {
get { return values; }
set {
values = value;
readOnlyValues = null;
}
}
ReadOnlyCollection<object> IParam.Values {
get { return readOnlyValues ?? (readOnlyValues = CreateReadOnlyCollection(Values)); }
set { Values = GetWritableCollection(value); /* тут возможно "непонятка", но её не избежать */ }
}
А>}
Код методов CreateReadOnlyCollection и GetWritableCollection достаточно прост, напиши, если не справишся и он понадобится, завтра подскажу.
"Непонятка" состоит в том, что такой вот код, к удивлению, не сработает:
но её не избежать — надо изменить интерфейс Param<T> или IParam. Как это сделать лучше — предсказать не возьмусь без детального знания имеющегося и требуемого кода.
P.S. Давай всё-таки повнимательней с оформлением кода в сообщениях — когда хочешь написать аккуратный ответ и приходится исправлять форматирование спрашивающего, то на ум приходит много интересных слов :о)
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Вопрос по дженерикам
От:
Аноним
Дата:
22.09.09 07:32
Оценка:
Здравствуйте, _FRED_, Вы писали:
_FR>Тогда альтернатива:
_FR>
А каким образом лучше узнавать какого типа этот object??
if (typeof(Int32).Equals(obf.GetType()))
_FR>Кстати, обычно такие события именую как Changed или Changing, в зависимости от того, приходят они после фактического изменения значения (первый вариант) или перед изменением (часто, аргументы таких событий позволяют отменить грядущее изменение).
Спасибо
_FR>Вариантов несколько. Основное — надо предоставить типонезависимый доступ к экземпляру Param. Например, так:
_FR>
_FR>interface IParam
_FR>{
_FR> String Name { get; set; }
_FR> ReadOnlyCollection<object> Values { get; set; }
_FR>}
А>>class Param<T> : IParam
А>>{
_FR> private IList<T> values;
_FR> private ReadOnlyCollection<object> readOnlyValues;
А>> String Name { get; set;} // сделаем эти члены свойствами, а не полями
А>> List<T> Values {
_FR> get { return values; }
_FR> set {
_FR> values = value;
_FR> readOnlyValues = null;
_FR> }
_FR> }
_FR> ReadOnlyCollection<object> IParam.Values {
_FR> get { return readOnlyValues ?? (readOnlyValues = CreateReadOnlyCollection(Values)); }
_FR> set { Values = GetWritableCollection(value); /* тут возможно "непонятка", но её не избежать */ }
_FR> }
А>>}
_FR>
Ага, тоесть "наружу" мы предоставляем список с типом object а внутри у нас список с указанным типом T?
_FR>Код методов CreateReadOnlyCollection и GetWritableCollection достаточно прост, напиши, если не справишся и он понадобится, завтра подскажу.
_FR>но её не избежать — надо изменить интерфейс Param<T> или IParam. Как это сделать лучше — предсказать не возьмусь без детального знания имеющегося и требуемого кода.
Тоесть доступ к Values нам надо получать через приведение к интерфейсу??
Тогда вот такой код компилируется
Param<int> paramInt = new Param<int>();
((IParam)paramInt).Values = new ReadOnlyCollection<object>(new object[] { "1", "2", "3", "4", "5", "6", "7" });
_FR>P.S. Давай всё-таки повнимательней с оформлением кода в сообщениях — когда хочешь написать аккуратный ответ и приходится исправлять форматирование спрашивающего, то на ум приходит много интересных слов :о)
Посыпаю голову пеплом
А>А каким образом лучше узнавать какого типа этот object??
Результатом операции "какого типа" должен быть тип, поэтому правильный ответ "obj.GetType()"
А>if (typeof(Int32).Equals(obf.GetType()))
Узнать, записано ли в переменной значение, которое имеет тип int можно так: "obj is int".
_FR>>Вариантов несколько. Основное — надо предоставить типонезависимый доступ к экземпляру Param. Например, так:
А>Ага, тоесть "наружу" мы предоставляем список с типом object а внутри у нас список с указанным типом T?
Что с наружи, что изнутри, тебе виднее, но на — там, где требуется типизированный подход, предоставляем типизтрованный интерфейсж; там, где нужен не-типизтрованный, используем object и т.п. Одно ограничение — нетипизированный список я сделал read-only, можно и не-ридонли, но могут возникнуть ошибки, когда в нетипизированный список добавят данные неожидаемого типа.
_FR>>Код методов CreateReadOnlyCollection и GetWritableCollection достаточно прост, напиши, если не справишся и он понадобится, завтра подскажу. А>Что то типа такого??
Ага
А>Тоесть доступ к Values нам надо получать через приведение к интерфейсу?? А>Тогда вот такой код компилируется
Именно в таком виде данный код использовать нецелесообразно — у переменной paramInt есть типизированные Values. А вообще: код, которому нужен нетипизированный доступ должен работать через интерфейс. При этом явное "приведение к интерфейсу" делать не нужно. Например, у нас есть Param<int> и метод, который требует нетипизированный IParam:
void Method(IParam param) {
foreach(var item in param.Values) {
// some work…
}//for
}
void Method2() {
var paramInt = new Param<int>();
Method(paramInt); /* никакого "явного приведения к интерфейсу" */
}
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Аноним, Вы писали:
А>Привет. А>Можно ли делать Events в виде дженериков? Суть в том что есть сообщение об изменении параметров, вот эти параметры могут быть различных типов.
Нет. Свойства и события не могут быть обобщёнными.
А>но так на каждый тип придется добавлять Event. Не хочется так
А зачем? Каким обработчиком будут обрабатываться эти евенты?
Если будет один обработчик на всех, то нужно делать object. Если обработчик должен вешаться на конкретный параметр, то это будет отдельное событие, а у конкретного параметра всегда есть тип.
Единственное, для чего такое подходит — это обработчики типа "изменения всех целых параметров". Непохоже, чтобы это имело физический смысл.
Но для него можно эмулировать event. Это же всего лишь пара методов — Add и Remove.
А>И еще. А>Допустим есть класс, который хранит имя параметра и допустимые значения, что то типа такого А>
А>Хочу хранить эти параметры в List<Param>.
Для чего? Какая обработка планируется для этого списка? Есть подозрение, что можно обойтись object там, где вы пишете T.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.