Я начал использовать преимущества C# 2.0, а именно анонимными делегатами
Допустим у нас есть такой код
/// какой-то интерфейс public interface IFoo {
void DoSomething(int something);
}
/// класс-пользователь интерфейса IFoopublic class FooUser {
public void UseFoo(IFoo foo) {
foo.DoSomething(0);
}
}
можно попробовать классический способ — сделат несколько наследников от IFoo
/// вариант с подклассами- наследниками от интерфеса IFoopublic class Example_WithSubClasses {
// класс-наследник 1public class Foo1 : IFoo {
public void DoSomething(int something) {
// делаем это первым способом
}
}
// класс-наследник 2public class Foo2 : IFoo {
public void DoSomething(int something) {
// делаем это по-другому
}
}
// пример использованияpublic void Example() {
IFoo foo;
FooUser user = new FooUser();
// делаем это первым способом
foo = new Foo1();
user.UseFoo(foo);
// делаем это по-другому
foo = new Foo2();
user.UseFoo(foo);
}
}
Но каждый раз писать новый наследник лениво. Можно написать один наследник на все случаи жизни, используя второй способ
/// вариант с анонимными делегатамиpublic class Example_WithDelegates {
// класс-наследник, он будет один на все случаиpublic class FooDelegate : IFoo {
public delegate void DoSomethingDelegate(int something);
private DoSomethingDelegate _doSomething;
// в конструктор передаем делегат, который будет вызываться при вызове IFoo.DoSomething()public FooDelegate(DoSomethingDelegate doSomething) {
_doSomething = doSomething;
}
// IFoo.DoSomething()public void DoSomething(int something) {
_doSomething(something);
}
}
// пример использованияpublic void Example() {
FooUser user = new FooUser();
user.UseFoo(new FooDelegate(delegate(int something) {
// делаем это первым способом
}));
user.UseFoo(new FooDelegate(delegate(int something) {
// делаем это по-другому
}));
}
}
Вопрос: какой способ лучше и понятнее? Не будет ли второй вариант труден для понимания?
Правило наименьшего удивления: Программа должна работать так, чтобы это вызывало наименьшее удивление у пользователя.
Построй свой мини-горд на http://rumactep.myminicity.com/
Не совсем хороший пример, ИМХО... Больше похоже на даунгрейд рефакторинга. На мой взгляд, это замена некоего патерна, который присутствовал в виде конкретной реализации интерфейса IFoo, размазыванием кода по другому классу.
Вообще-то, анонимные делегаты — это хорошо, в умелых руках
Здравствуйте, RUMACTEP, Вы писали:
RUM>Вопрос: какой способ лучше и понятнее?
По большому счёту — только в возможности расширить интерфейс (добавить ещё один метод\свойство\событие).
RUM>Не будет ли второй вариант труден для понимания?
Не должен, хотя кому-как, но, в связи с надвигающимся уклоном в сторону функционального стиля, не дожен быть труден.
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, RUMACTEP, Вы писали:
RUM>Я начал использовать преимущества C# 2.0, а именно анонимными делегатами
1. Нет никаких анонимных делегатов. Есть анонимные методы. Это в МС шутники юмора завеслись. Ради экономии ключевых слов повторно использовали (бездумно) для этих целей ключевое слово delegate.
2. Анонимные методы намного более удобный инструмен для специализации алгоритмов и т.п. "кусками логики". Правда хранить их в полях не лучшая идея. Намного удлобнее передавать их в качестве параметра. Это получается короче, яснее и гибче.
3. Кайф анонимных методов в том, что они допускают лексические замыкания. То есть в анонимном методе можено напрямую использовать любую переменную или фунцию видимую из точки его объявления. Это позволяет порождать очень простой в понимании и гибкий код.
4. В большинстве случаев при предаче анонимного метода в качестве парамтера нет нужды явно создавать делегат. C# сам приведет метод к нужному делегату. Его тип он выведет из типа параметра или переменной.
В C# 3.0 идея анонимных методов будет развита еще сильнее. Появятся лямбды с намного более крактим синтаксисом. И в купе с новой библиотекой Linq они позволят существенно сократить объем кода при работе с коллекциями и БД.
RUM>Но каждый раз писать новый наследник лениво. Можно написать один наследник на все случаи жизни, используя второй способ RUM>
RUM>/// вариант с анонимными делегатами
RUM>public class Example_WithDelegates {
RUM> // класс-наследник, он будет один на все случаи
RUM> public class FooDelegate : IFoo {
RUM> public delegate void DoSomethingDelegate(int something);
RUM> private DoSomethingDelegate _doSomething;
RUM> // в конструктор передаем делегат, который будет вызываться при вызове IFoo.DoSomething()
RUM> public FooDelegate(DoSomethingDelegate doSomething) {
RUM> _doSomething = doSomething;
RUM> }
RUM> // IFoo.DoSomething()
RUM> public void DoSomething(int something) {
RUM> _doSomething(something);
RUM> }
RUM> }
RUM> // пример использования
RUM> public void Example() {
RUM> FooUser user = new FooUser();
RUM> user.UseFoo(new FooDelegate(delegate(int something) {
RUM> // делаем это первым способом
RUM> }));
RUM> user.UseFoo(new FooDelegate(delegate(int something) {
RUM> // делаем это по-другому
RUM> }));
RUM> }
RUM>}
RUM>
А смыслв в этой обертке? Смотри как красиво можно жить передавая все что нужно в качестве парамтера.
Например:
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main()
{
int max = 50;
List<int> list = new List<int>(new int[] { 1, 200, 3, 4, 5, 6, 78, 190 });
Console.WriteLine(ToString(Filter(list, delegate(int x) { return x < max; }), ", ")); // анонимный метод замыкается на перменную max!
}
static string ToString<T>(IEnumerable<T> seq, string separator)
{
StringBuilder sb = new StringBuilder();
foreach (T value in seq)
{
sb.Append(value);
sb.Append(separator);
}
if (sb.Length > 0)
sb.Length -= separator.Length;
return sb.ToString();
}
static IEnumerable<T> Filter<T>(IEnumerable<T> seq, Predicate<T> predicate)
{
foreach (T value in seq)
if (predicate(value))
yield return value;
}
}
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Чем анонимные делегаты лучше наследования?
От:
Аноним
Дата:
23.09.06 08:40
Оценка:
Console.WriteLine(ToString(Filter(list, delegate(int x) { return x < max; }), ", ")); // анонимный метод замыкается на перменную max!
Подскажите, а как эту строку реализовать на VB.Net ?
Здравствуйте, RUMACTEP, Вы писали:
RUM>Вопрос: какой способ лучше и понятнее? Не будет ли второй вариант труден для понимания?
Оба способа хороши. К примеру, в ASP.NET 2.0 есть такой интерфейс — ITemplate.
Можно честно реализовывать его в своем классе.
А есть класс CompiledTemplateBuilder : ITemplate.
Он очень удобен, когда нужен "одноразовый" шаблон.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Чем анонимные делегаты лучше наследования?
От:
Аноним
Дата:
25.09.06 08:34
Оценка:
Посмотрел Рефлектором как реализуется строка: yield return value ...
и выпал в осадок!
Компилятор генерит целый класс! Почему бы на VB так ни сделать?
Блин, дискриминация какая то!!!