Когда использовать Duck Typing?

Вопрос

Я уже много читал о Duck Typing и, кажется, понимаю эту концепцию.

Я не понял, в каком случае действительно имеет смысл отказаться от преимуществ строго типизированного программирования в пользу преимуществ Duck Typing. В каком случае можно использовать Duck Typing вместо интерфейсов и наследования?

Я имею в виду, что если вам все равно нужно обеспечить, чтобы объект, переданный методу, реализовывал определенные методы, почему бы мне просто не определить интерфейс?

Чтобы быть ясным, я знаю, как работает Duck Typing. Я хочу знать, когда действительно имеет смысл его использовать.

Уточнение:

В этом случае вы бы использовали

public bool MyMethod(dynamic obj)

вместо

public bool MyMethod(ISomeInterface obj)
//or
public bool MyMethod(SomeBaseClass obj)

person LuckyLikey    schedule 03.06.2015    source источник
comment
Учитывая, что во всем .NET существует всего четыре или пять типов утки (foreach, await, LINQ, инициализаторы коллекций), и все они реализованы на стороне компилятора, я не понимаю вашего вопроса.   -  person xanatos    schedule 03.06.2015
comment
haacked.com/archive / 2007/08/19 / - здесь есть раздел под названием «Очень полезный вариант использования, когда вы можете использовать утиный ввод»   -  person Alex    schedule 03.06.2015
comment
Я считаю, что вам следует изменить свой вопрос на то, когда использовать динамическое ключевое слово   -  person Dimitar Tsonev    schedule 03.06.2015
comment
когда его действительно имеет смысл использовать - очевидно, когда вы не можете использовать наследование или наследование дороже, чем утиная печать.   -  person Dennis    schedule 03.06.2015
comment
Ах ... теперь яснее. Никогда не думай об этом. Если только вы не наберете сотни строк кода.   -  person xanatos    schedule 03.06.2015
comment
Если вы не хотите гореть в аду, не используйте dynamic. Это моё собственное мнение. И в 1,5 миллионах написанных мной исходных кодов os есть 2-3 использования dynamic.   -  person General-Doomer    schedule 03.06.2015
comment
Если вы думаете, что вам это нужно, вам это не нужно. Если вы без тени сомнения знаете, что он вам действительно нужен, то, вероятно, он вам все равно не нужен, и вы просто неправильно применяете принципы наследования.   -  person C Bauer    schedule 03.06.2015
comment
Избегайте, избегайте, избегайте! Но ... Я написал DynamORM, который много использует эту концепцию, и, исходя из этого опыта, должен сказать, что это очень плохо. Подумайте 10 раз, прежде чем использовать. Динамика - это круто, когда вы создаете какой-то бэкэнд и не знаете, какой конечный результат вам бросает разработчик, например, COM или общая структура / класс, с которыми вы должны иметь дело.   -  person dr4cul4    schedule 03.06.2015
comment
@ General-Doomer ... можно сказать то же самое о двойном негативе? :п   -  person Cool Blue    schedule 12.12.2016
comment
@Cool Blue Я русский, в нашей речи мы используем двойные (даже тройные) негативы =)   -  person General-Doomer    schedule 13.12.2016


Ответы (3)


C # имеет строгую типизацию не просто так. Если у вас нет веской причины (например, необходимость взаимодействия с COM) для использования типа dynamic, вам, вероятно, следует избегать его как чумы, иначе вы рискуете превратить проблемы времени компиляции в проблемы времени выполнения. dynamic - мощный инструмент, которым легко злоупотребить. Хорошо подумайте, действительно ли вам нужна динамическая типизация - если вы думаете, что она есть, есть вероятность, что вы с самого начала решаете проблему неправильно и вам нужно реорганизовать код.

Чтобы конкретно ответить на ваш вопрос - один из возможных вариантов использования был, если вы писали код сериализации и вам нужно было принять десериализованный объект, например десериализованную структуру JSON из запроса веб-API. Такие методы должны будут обрабатывать любой переданный им тип, что является ситуацией, в которой использование dynamic лучше, чем альтернатива (т. Е. Грузовик с отражением).

Другой пример, который я могу придумать, - это совместимость с языками, в частности, в среде выполнения динамического языка (например, JavaScript, IronPython, IronRuby, ...), и необходимо написать метод, принимающий типы из таких языков.

Из Начало программирования на Visual C # 2012:

Для большей части кода C #, который вы пишете, избегайте ключевого слова dynamic. Однако, если возникает ситуация, когда вам нужно его использовать, пользуйтесь и любите - и подумайте о тех бедных программистах прошлого, которые не имели в своем распоряжении этого мощного инструмента.

person Tom Galvin    schedule 03.06.2015
comment
Если он ходит как утка и крякает как утка, то это мог быть я. - person Tom Galvin; 22.02.2016

Утиная типизация часто используется в C #, вы просто не подозреваете об этом большую часть времени. Компилятор часто использует его под прикрытием для операторов foreach, для Linq, для awaitи для инициализаторов коллекций. Этот вопрос подробно его подробно описывает.

Другой способ использовать утиный ввод - использовать ключевое слово dynamic. И давайте будем откровенны, вам следует избегать этого как можно больше. Но очень полезно взаимодействовать с динамическими языками / контекстами. Например, предположим, что вы вызываете веб-службу, которая отвечает плохо определенным json (поэтому вы не можете легко десериализовать ее до известного класса). Возможно, вам будет намного проще разобрать его как JObject с помощью json.Net и использовать этот JObject как dynamic.

dynamic myParsedJson = JObject.Parse(json);
string theStringImLookingFor = myParsedJson.foo.bar.blah.nicestring;

Другой вариант использования - модели просмотра ASP.net MVC. Наличие динамической модели просмотра может быть очень мощным. Orchard CMS интенсивно использует его, и даже если это немного сложно понять, во-первых, он позволяет использовать очень эффективные варианты использования.

Также на ум приходит COM-взаимодействие.

person Falanwe    schedule 03.06.2015

Утиный ввод:

Пожалуйста, сделайте это, а не спрашивайте, кто вы.

Пример:

Здесь кодирование должно быть просто определением и исполнением. Например, вот что я хочу, чтобы следующий объект что-то сделал.

    Please("Walk", new Dog());
    Please("Run", new Duck());
    Please("Fly", new Cup());
    Please("Fly", new Bird());
    Please("Fly", new Man());
    Please("Walk", new Man());
    Please("Run", new Man());

Это результат после выдачи теста.

введите описание изображения здесь

Итак, вышеуказанные объекты будут делать только то, что мы просим. Дополнительно я добавил вопрос, чтобы спросить их, кто они тоже. Вот код на C #.

private void Please(string Action, object Obj)
{
    MethodInfo method = Obj.GetType().GetMethod(Action, Type.EmptyTypes, null);
    if (method != null)
    {
        method.Invoke(Obj, new object[] { });
    }
    else
    {
        Console.WriteLine(string.Format("I can not {0} because {1}", Action, WhoAreYou(Obj)));
    }
}

private string WhoAreYou(object unknown)
{
    string question = "WhoAreYou";
    MethodInfo whoAreYou = unknown.GetType().GetMethod(question, Type.EmptyTypes, null);
    return whoAreYou.Invoke(unknown, new object[] { }).ToString();
}
person Khachornchit Songsaen    schedule 26.11.2017
comment
ty за то, что поделились этой концепцией. Это указывает на интересный вариант использования. - person LuckyLikey; 17.01.2019