Что такое - одна и несколько отправок (по отношению к .NET)? - PullRequest
7 голосов
/ 26 января 2009

Это то же самое, что перегрузка, если нет, не могли бы вы предоставить и пример каждого в C #

Я прочитал ответы на аналогичный вопрос, заданный в SO ... Я не понял ответы, отправленные на него.

Подобный вопрос задан здесь

РЕДАКТИРОВАТЬ: С новым ключевым словом "dynamic" в C # 4.0 ... это позволит включить язык "multi dispatch"?

Ответы [ 9 ]

5 голосов
/ 26 января 2009

Многократная отправка - это «форма» перегрузки ...

Например, C # - это одна отправка, потому что, если выясняется, какой метод вызывать, основываясь только на одном аргументе, указатель this. Когда у вас есть что-то вроде этого:

Base base= new Derived();
base.DoSomething();

метод Derived.DoSomething вызывается, даже если вы вызывали его через базовый указатель. Теперь, если у нас есть следующее:

class Derived : Base
{
  public override void Process(Stream stream);
  public override void Process(FileStream stream);
  public override void Process(MemoryStream stream);
}

И мы делаем это:

Stream stream= new MemoryStream(...);
Base b= new Derived();
b.Process(stream);

Затем мы вызовем метод Process (Stream) из Derived, поскольку C # выполняет однократную отправку указателя объекта (b), а затем использует информацию времени компиляции, чтобы решить, какой метод вызвать. Даже если stream является MemoryStream, одна диспетчерская система будет игнорировать это.

В мультидиспетчерской системе будет рассмотрен указатель объекта (как в C #) И будут рассмотрены типы аргументов во время выполнения. В приведенном выше примере, поскольку stream на самом деле является MemoryStream, система будет вызывать метод Process (MemoryStream) .

5 голосов
/ 26 января 2009

C # использует одну отправку, которая включает перегруженные методы. Когда у вас есть код

stringBuilder.Append(parameter);

диспетчер просматривает все методы, определенные в классе stringBuilder, и находит правильный.

Для примера с несколькими рассылками, давайте посмотрим на Пролог (который является первым, о котором я могу подумать). Вы можете определить функцию в прологе так:

func(Arg1, Arg2) :- ....body....

Это не определено ни в каком классе, но в глобальной области видимости. Затем вы можете вызвать func(Arg1, Arg2) для любых двух аргументов, и эта функция будет вызвана. Если вы хотите что-то вроде перегрузки, вы должны проверить типы аргументов внутри функции и определить это несколько раз:

func(Arg1, Arg2) :- is_number(Arg1), is_string(Arg2), ....body....
func(Arg1, Arg2) :- is_string(Arg1), is_list(Arg2), ....body....
func(Arg1, Arg2) :- is_number(Arg1), is_list(Arg2), ....body....

Затем будут проверены любые два типа аргументов, которые вы отправите, - это часть множественной отправки.

Короче говоря, одиночная отправка просматривает только методы, определенные в первом аргументе (в нашем первом примере, stringBuilder), а затем разрешает правильную перегрузку для вызова с использованием других аргументов. Множественная диспетчеризация имеет методы / функции, определенные в глобальной области, и обрабатывает все аргументы одинаково во время разрешения перегрузки.

Надеюсь, я дал понять, что это довольно сложный вопрос.


Обновление: я забыл упомянуть, многократная отправка происходит во время выполнения, тогда как одиночная отправка происходит во время компиляции.
Обновление № 2: По-видимому, это было не так.

2 голосов
/ 26 января 2009

Многоотправка связана с перегрузкой метода, но не одинакова. Первый - динамическое решение во время выполнения, второй - статическое решение во время компиляции. Таким образом, есть неоспоримое преимущество в гибкости, но, следовательно, затраты на многопотоковую обработку.

AFAIK язык может поддерживать любой, но не оба, хотя оба могут быть смоделированы (multi-dispatch может быть смоделирована с посетителями) C # определяет типы данных во время компиляции и, следовательно, не является языком множественной диспетчеризации, поэтому примеры не возможны.

(предостережение: я не на 100%)


дополнение: на самом деле в Википедии есть статья , которая кажется довольно основательной, да и полезный пример LISP

1 голос
/ 26 января 2009

В ОО томится текст:

SomeType b;
a = b.Foo(c, d)

Означает, что объекту b передается сообщение Foo с параметрами c и d. Одиночная отправка означает, что только ОДИН аспект этой системы отвечает за определение во время выполнения, какой (из многих возможных) методов Foo будет фактически вызван.

Модель java, c # и большинство других языков ОО использует то, что только тип времени выполнения 'b' может 'решить', что является фактическим вызовом метода. Таким образом, если у вас есть две реализации SomeType, каждая из которых обеспечивает различную реализацию Foo, тогда решение о том, что использовать, основано исключительно на том, какой тип b окажется в этой точке. ЕСЛИ существует несколько перегрузок Foo, то решение о том, какую перегрузку использовать, является решением времени компиляции, основанным исключительно на типах времени компиляции b, c и d.

Это одна отправка, единственная точка выбора - система типов, связанная с b.

Множественная отправка позволила бы во время выполнения позволить типам времени выполнения b, c и d решать, какой метод вызывать (такое решение неизбежно является более сложным).

В более динамичной системе, где концепция четко определенных типов является более гибкой (скажем, система, основанная на прототипах, а не на модели наследования, которую вы знаете из c ++ / java / C #), тогда вместо этого принимается решение о том, какой метод вызывать быть полностью в соответствии с фактическими примерами b, c и d.

1 голос
/ 26 января 2009

Одиночная / множественная отправка - это своего рода перегрузка во время выполнения. Одиночная отправка более известна как виртуальные функции. Точная функция, вызываемая при вызове виртуальной функции, определяется на основе типа объекта во время выполнения. Двойная диспетчеризация - это то же самое, что распространяется на работу с двумя объектами - обычно это параметр this и второй параметр. Вы можете реализовать это без особых сложностей, используя Vistor Pattern. Многократная диспетчеризация еще больше расширяет эту концепцию до большего количества параметров, но ее значительно сложнее реализовать в таких языках, как C # (не то, что это невозможно сделать, это просто сложно). Некоторые языки реализуют эту способность прямо из коробки.

например. в .NET функция ToString () является примером однократной отправки

// Single dispatch
Object o = GetSomeObject(); // Return SomeType casted to Object.
o.ToString(); // Call SomeType::ToString instead of just Object::ToString

// Double dispatch (this version won't work in C#)
Shape s1 = GetSquare();
Shape s2 = GetCircle();
s1.Intersects(s2); // If C# supported double dispatch, this would call Square::Intersects(Circle) not Square::Intersects(Shape)
0 голосов
/ 27 января 2011

Вы можете использовать динамическое ключевое слово для реализации множественной диспетчеризации в C #.

interface IA { }
interface IB { }
class CA1 : IA {}
class CA2 : IA {}
class CA11 : CA1 {}
class CB1 : IB {}
class CB2 : IB {}

class MD
{
    public enum X { X } ;
    public static void Foo(IA a, IB b, X dispatch = X.X) { Foo((dynamic)a, (dynamic)b); }
    static void Foo(IA a, IB b) { Console.WriteLine("IA IB"); }
    static void Foo(CA1 a, CB1 b) { Console.WriteLine("CA1 CB1"); }
    static void Foo(CA2 a, CB1 b) { Console.WriteLine("CA2 CB1"); }
    static void Foo(CA1 a, CB2 b) { Console.WriteLine("CA1 CB2"); }
    static void Foo(CA2 a, CB2 b) { Console.WriteLine("CA2 CB2"); }
    static void Foo(CA11 a, CB2 b) { Console.WriteLine("CA11 CB2"); }
}
class Program
{
    static void Main(string[] args)
    {
        var a1 = new CA1();
        var a11 = new CA11();
        var a2 = new CA2();
        var b1 = new CB1();
        var b2 = new CB2();
        MD.Foo(a1, b1);
        MD.Foo(a2, b1);
        MD.Foo(a1, b2);
        MD.Foo(a2, b2);
        MD.Foo(a11, b1);
        MD.Foo(a11, b2);
    }
}

Разрешение Foo ((динамическое) a, (динамическое) b)) выполняется во время выполнения и выбирает один из перегруженных методов Foo на основе конкретных типов «a» и «b».

0 голосов
/ 17 ноября 2009

Извините, пример, который я привожу, пока не ошибся. Это не правильная версия:

class Wheel
{
    public void RepairWhell() { }
}

class Chassis
{
    public void RepairChassis() { }
}

class Engine
{
    public void RepairEngine() { }
}

class CarWorkshop
{
    public string Repair(Wheel value)
    {
        value.RepairWhell();
        return "wheel repaired";
    }
    public string Repair(Chassis value)
    {
        value.RepairChassis();
        return "chassis repaired";
    }
    public string Repair(Engine value)
    {
        value.RepairEngine();
        return "engine repaired";
    }
}

class Program
{
    static void Main(string[] args)
    {
        var carWorkshop = new CarWorkshop();

        dynamic whell = new Wheel();
        dynamic chassis = new Chassis();
        dynamic engine = new Engine();

        Console.WriteLine(carWorkshop.Repair(whell));
        Console.WriteLine(carWorkshop.Repair(chassis));
        Console.WriteLine(carWorkshop.Repair(engine));
        Console.ReadLine();
    }
}

Так что ответ это да. C # обеспечивает несколько отправлений.

0 голосов
/ 17 ноября 2009

В c # 4.0 мультиметоды включены с новым динамическим ключевым словом:

с использованием системы; Пример пространства имен { Колесо класса { public void RepairWhell () {} }

class Chassis
{
    public void RepairChassis() { }
}

class Engine
{
    public void RepairEngine() { }
}

class CarWorkshop
{
    public string Repair(Wheel value)
    {
        value.RepairWhell();
        return "wheel repaired";
    }
    public string Repair(Chassis value)
    {
        value.RepairChassis();
        return "chassis repaired";
    }
    public string Repair(Engine value)
    {
        value.RepairEngine();
        return "engine repaired";
    }
}

class Program
{
    static void Main(string[] args)
    {
        dynamic carWorkshop = new CarWorkshop();

        var whell = new Wheel();
        var chassis = new Chassis();
        var engine = new Engine();

        Console.WriteLine(carWorkshop.Repair(whell));
        Console.WriteLine(carWorkshop.Repair(chassis));
        Console.WriteLine(carWorkshop.Repair(engine));
        Console.ReadLine();
    }
}

}

Динамическое внедрение мультиметодов, очень мощная парадигма в c #.

0 голосов
/ 26 января 2009
#include <iostream>

class Pet {
};

class Cat: public Pet {
};

class Dog: public Pet {
};

class Human {
};

class Man : public Human {
        public:
                void Kick(Cat& victim);
                void Kick(Dog& victim);
};

class Woman : public Human {
        public:
                void Kick(Cat& victim);
                void Kick(Dog& victim);
};

void Man::Kick(Cat& victim) {
        std::cout << "Meow!!!" << std::endl;
}

void Woman::Kick(Cat& victim) {
        std::cout << "I won't kick a cat" << std::endl;
}

void Man::Kick(Dog& victim) {
        std::cout << "I won't kick a dog" << std::endl;
}

void Woman::Kick(Dog& victim) {
        std::cout << "Woof!!!" << std::endl;
}

int main(int argc, char** argv) {
        Man kicker;
        Dog victim;
        Pet zoo[] = { victim };
        kicker.Kick(victim);
//      kicker.Kick(zoo[0]);   // No multimethods
        return 0;
}

На данный момент C ++ не может определить во время выполнения, является ли Pet на самом деле Cat или Dog.

Если бы был какой-то способ сделать это во время выполнения (чтобы вышеприведенный код компилировался с закомментированной строкой), было бы сказано, что C ++ поддерживает множественную диспетчеризацию или мультиметоды.

...