C# 4.0: Мультиметоды
С появлением в С# 4 dynamic нам уже рассказали как здорово можно будет работать с COM-объектами, и динамическими языками. Однако, с помощью dynamic можно делать и совершенно другие интересные вещи :)
Итак, что же такое мультиметоды. В сети много информации, однако подана она совершенно зубодробительным и непонятным образом, со страшными словами типа multiple dispatching.
По-хорошему, слова эти надо знать. Хотя есть и другие мнения на этот счет. Недавно вот прочитал на веселом ресурсе habrahabr.ru про то, что “Паттерны – это рутины, для тех, кто не умеет программировать”. Рекомендую к прочтению, хорошее настроение обеспечено.
Самое простое определение мультиметодов, которое мне доводилось видеть, звучало так: Мультиметоды – это виртуальные методы, принадлежащие сразу нескольким классам. А объяснять долго не буду, просто посмотрите на код
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4
5 namespace NewC4FeaturesTest
6 {
7 class A {}
8
9 class B : A {}
10
11 class C : A {}
12
13 class Program
14 {
15 static void Main(string[] args)
16 {
17 Program.Dispatch(new B(), new C());
18 Console.ReadLine();
19 }
20
21 public static void Dispatch(A a, A b)
22 {
23 dynamic x = a;
24 dynamic y = b;
25 multiMethod(a, b);
26 multiMethod(x, y);
27 }
28
29 private static void multiMethod(A a, A b)
30 {
31 Console.WriteLine(string.Format("A and A"));
32 }
33
34 private static void multiMethod(B a, A b)
35 {
36 Console.WriteLine(string.Format("B and A"));
37 }
38
39 private static void multiMethod(A a, C b)
40 {
41 Console.WriteLine(string.Format("A and C"));
42 }
43
44 private static void multiMethod(B a, C b)
45 {
46 Console.WriteLine(string.Format("B and C"));
47 }
48 }
49 }
Если у вас уже установлена Beta 2 Visual Studio 2010, можно скопипастить код, и посмотреть как он работает. Первый вызов всегда приведет к работе метода на строке 29 (“A and A”), по понятным причинам. А вот второй вызов в рантайме разберется, что надо вызвать метод на строке 44 (“B and C”).
Таким образом, можно избежать if’ов и switch’ей. Некоторые даже говорят, что это практически pattern matching light.
Однако, есть и темная сторона :) Если мы закомментируем строки 39 – 47, то второй вызов выведет нам “B and A” (строка 34). Понятно, почему это происходит – этот метод более специфичен, чем “A and A”. Однако, если мы раскомментируем 39 – 42, то второй вызов приведет к выбросу исключения. Потому что непонятно, какое совпадение аргумента важнее – B, или С.
Именно по такой причине прогрессивное человечество придумало Visitor. При этом мы должны гарантированно описать все комбинации, иначе компилятор даст нам по рукам. Но реализацию паттерна простой не назовешь.
Если все это показалось вам интересным, в следующий раз приведу реализацию Visitor с помощью dynamic.