[Этюд, C#] dynamic type inference
От: nikov США http://www.linkedin.com/in/nikov
Дата: 26.06.10 10:50
Оценка: 15 (4)
Что напечатает эта программа?

using System;

class A
{
    public static void Foo(dynamic d)
    {
        PrintType(d);
    }

    static void PrintType<T>(T x)
    {
        Console.WriteLine(typeof(T));
    }
}

class B
{
    struct S { }
    class C {}
    delegate void D();

    static void Main()
    {
        A.Foo(new S[0]);
        A.Foo(new C[0]);
        A.Foo(new D[0]);
    }
}
Re: [Этюд, C#] dynamic type inference
От: nikov США http://www.linkedin.com/in/nikov
Дата: 26.06.10 11:03
Оценка:
Можно немного расширить задачу:

static void Main()
{
    A.Foo(new S[0]);
    A.Foo(new C[0]);
    A.Foo(new D[0]);
        
    A.Foo(new Func<S>[0]);
    A.Foo(new Func<C>[0]);
    A.Foo(new Func<D>[0]);
}
Re[2]: [Этюд, C#] dynamic type inference
От: Пельмешко Россия blog
Дата: 27.06.10 22:48
Оценка: 68 (9)
Здравствуйте, nikov, Вы писали:

N>Что напечатает эта программа?


N>
N>using System;

N>class A
N>{
N>    public static void Foo(dynamic d)
N>    {
N>        PrintType(d);
N>    }

N>    static void PrintType<T>(T x)
N>    {
N>        Console.WriteLine(typeof(T));
N>    }
N>}

N>class B
N>{
N>    struct S { }
N>    class C {}
N>    delegate void D();

N>    static void Main()
N>    {
N>        A.Foo(new S[0]);
N>        A.Foo(new C[0]);
N>        A.Foo(new D[0]);
N>    }
N>}
N>


Когда запустил код этого этюда, то у меня случился когнитивный диссонанс и я был уверен, что наблюдаемое поведение — просто натуральный баг и успел отправить пару лучей кое-чего команде C# 4.0 dynamic

Ключом понимания этюда было знание о том, что nikov в стремлении к приданию этюду канонической формы, никогда бы не разбил этюд на два типа, если бы реально требовался только один

Итак код напечатает:
System.Array
System.Object[]
System.MulticastDelegate[]

В случае вызовов PrintType<T>(T x) с параметрами, типы которых известны на момент компиляции, компилятор будет выводить тип типа-параметра метода на момент компиляции. В случае с параметрами типа dynamic, процедура вывода типа-параметра будет отложен на момент исполнения, при этом поведение вывода типов времени исполнения стремится соответствовать статическому поведению настолько, насколько это возможно.

Чтобы приблизиться к статическому поведению, надо учитывать такую важную штуку, как область видимости типа. Фактически в качестве типа-параметра T метода PrintType() могут выступать любой из типов, видимых из всех методов, которым видим сам метод PrintType.

Теперь следует обратить внимание на то, что структура S, класс C и тип делегата D являются приватными nested-типами класса B и их область видимости не распространяется на метод A.Foo() В данной ситуации механизм dynamic начинает пытаться заменить тип на менее конкретный, используя неявные ссылочные преобразования и boxing-преобразования.



N>Можно немного расширить задачу:

N>static void Main()
N>{
N>    A.Foo(new Func<S>[0]);
N>    A.Foo(new Func<C>[0]);
N>    A.Foo(new Func<D>[0]);
N>}
N>


Код напечатает:
System.MulticastDelegate[]
System.Func`1[System.Object][]
System.Func`1[System.MulticastDelegate][]




Вот и всё, механизм dynamic просто находит первый наиболее конкретный видимый тип.

Отличный этюд!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.