それはオーバーロードと同じですか、そうでない場合は、C#でそれぞれの例を提供してください
SOで尋ねられた同様の質問への回答を読みました...それに投稿された回答を理解できませんでした。
ここで尋ねられた同様の質問
編集: C# 4.0 の新しい「動的」キーワードを使用すると、言語の「マルチ ディスパッチ」が有効になりますか?
それはオーバーロードと同じですか、そうでない場合は、C#でそれぞれの例を提供してください
SOで尋ねられた同様の質問への回答を読みました...それに投稿された回答を理解できませんでした。
ここで尋ねられた同様の質問
編集: C# 4.0 の新しい「動的」キーワードを使用すると、言語の「マルチ ディスパッチ」が有効になりますか?
複数のディスパッチは、オーバーロードの「形式」です...
たとえば、C# は単一ディスパッチです。これは、"this" ポインターという 1 つの引数のみに基づいてどのメソッドを呼び出すかを判断するためです。あなたがこのようなものを持っているとき:
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);
次に、C# がオブジェクト ポインター (b) で単一のディスパッチを行い、コンパイル時の情報を使用して呼び出すメソッドを決定するため、 Process(Stream)メソッドを呼び出します。streamDerived
が MemoryStreamであっても、単一のディスパッチ システムはこれを無視します。
マルチディスパッチ システムでは、オブジェクト ポインターが (C# のように) 調べられ、引数の実行時の型が調べられます。上記の例では、streamは実際には MemoryStream であるため、システムはProcess(MemoryStream)メソッドを呼び出します。
C#は、オーバーロードされたメソッドを含む単一のディスパッチを使用します。あなたがコードを持っているとき
stringBuilder.Append(parameter);
ディスパッチャは、stringBuilderのクラスで定義されているすべてのメソッドを調べて、正しいメソッドを見つけます。
多重ディスパッチの例として、Prolog(私が最初に思いついたもの)を見てみましょう。あなたはそのようにプロローグで関数を定義することができます:
func(Arg1, Arg2) :- ....body....
これは、クラス内ではなく、グローバルスコープで定義されます。次に、func(Arg1, Arg2)
任意の2つの引数を呼び出すことができ、この関数が呼び出されます。オーバーロードのようなものが必要な場合は、関数内の引数タイプを検証し、それを複数回定義する必要があります。
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....
次に、送信する2つの引数タイプの両方がチェックされます。つまり、多重ディスパッチ部分です。
つまり、シングルディスパッチは、最初の引数(最初の例ではstringBuilder)で定義されたメソッドのみを調べ、他の引数を使用して呼び出す正しいオーバーロードを解決します。多重ディスパッチには、グローバルスコープで定義されたメソッド/関数があり、過負荷の解決中にすべての引数を同じように扱います。
はっきりさせておきたいのですが、これはかなり難しいテーマです。
更新:言及するのを忘れました。実行時に複数のディスパッチが発生し、コンパイル時に単一のディスパッチが発生します。
更新#2:どうやら、それは真実ではありませんでした。
マルチディスパッチはメソッドのオーバーロードに関連していますが、同じではありません。前者は動的な実行時の決定であり、後者は静的なコンパイル時の決定です。暗黙的に柔軟性の利点がありますが、したがって、マルチディスパッチにはパフォーマンスコストがかかります。
AFAIK言語はどちらか一方をサポートできますが、両方をサポートすることはできませんが、両方をシミュレートできます(マルチディスパッチは訪問者と一緒にシミュレートできます)。C#はコンパイル時にデータ型を決定するため、マルチディスパッチ言語ではないため、例はありません。
(注意:私はこれについて100%ではありません)
補遺:実際、ウィキペディアにはこれに関する記事がありますが、これはかなり徹底的で、ああ、役立つLISPの例のようです。
シングル/マルチディスパッチは、実行時のオーバーロードの一種です。シングルディスパッチは、より一般的には仮想関数として知られています。仮想関数を呼び出すときに呼び出される正確な関数は、オブジェクトの実行時型に基づいて決定されます。ダブルディスパッチも同じで、2つのオブジェクト(通常はthis
パラメーターと2番目のパラメーター)で機能するように拡張されています。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)
OO言語では、テキストは次のとおりです。
SomeType b;
a = b.Foo(c, d)
オブジェクトbにパラメータcとdのメッセージFooが渡されていることを意味します。シングルディスパッチとは、このシステムの1つの側面のみが、実行時にFooが実際に呼び出される(おそらく多くの)メソッドを決定する責任があることを意味します。
java、c#、および他のほとんどのオブジェクト指向言語が使用するモデルは、実行時型の「b」のみが実際のメソッド呼び出しを「決定」するというものです。したがって、SomeTypeの2つの実装があり、どちらもFooの異なる実装を提供する場合、どちらを使用するかは、その時点でどちらのタイプbが発生するかにのみ基づいて決定されます。Fooのオーバーロードが複数ある場合、使用するオーバーロードの決定は、コンパイル時の既知のタイプb、c、およびdのみに基づくコンパイル時の決定です。
これは単一のディスパッチであり、選択の単一のポイントはbに関連付けられた型システムです。
多重ディスパッチを使用すると、実行時に、実行時のタイプb、c、およびdで、呼び出すメソッドを決定できます(このような決定は必然的に複雑になります)。
明確に定義された型の概念がより流動的であるより動的なシステム(たとえば、c ++ / java / C#から知っている継承モデルではなくプロトタイプに基づくシステム)では、呼び出すメソッドに関する決定は完全に上向きになります実際のインスタンスb、c、およびdに。
申し訳ありませんが、間違える前に私が挙げた例です。正しいバージョンではありません:
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#はマルチディスパッチを提供します。
#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++ は実行時に aPet
が実際に a なのCat
かa なのかを判断できませんDog
。
実行時にそれを行う何らかの方法がある場合 (上記のコードがコメント行をコメント解除してコンパイルされるようにするため)、C++ は複数のディスパッチまたはマルチメソッドをサポートすると言われます。
c# 4.0 では、新しい dynamic キーワードでマルチメソッドが有効になります。
システムを使用して; 名前空間の例 { 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)
{
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# では、非常に強力なパラダイムであるマルチメソッドを動的に導入します。
dynamic キーワードを使用して、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((dynamic)a,(dynamic)b)) の解決は実行時に行われ、'a' と 'b' の具象型に基づいてオーバーロードされた Foo メソッドの 1 つが選択されます。