C# uses single dispatch, which includes overloaded methods. When you have the code
stringBuilder.Append(parameter);
the dispatcher looks at all methods defined on the stringBuilder's class, and finds the correct one.
For a multiple dispatch example, let's look at Prolog (which is the first one I could think of). You can define a function in prolog as such:
func(Arg1, Arg2) :- ....body....
This is not defined inside any class but in a global scope. Then, you can call func(Arg1, Arg2)
on any two arguments and this function will be called. If you want something like overloading, you have to validate the argument types inside the function, and define it multiple times:
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....
Then, any two argument types you would send would both be checked - that is the multiple dispatch part.
In short, single dispatch only looks at methods defined on the first argument (in our first example, the stringBuilder), then resolves the correct overload to call using the other arguments. Multiple dispatch has methods/functions defined in the global scope and treats all arguments the same during overload resolution.
I hope I made myself clear, this is a pretty tough subject.
Update: I forgot to mention, multiple dispatch happens at runtime while single dispatch happens at compile time.
Update #2: Apparently, that was not true.