In C#, is it possible to have an object that has multiple method signatures for an Action<> or delegate? Like this:
class Foo
{
public Action<string> DoSomething;
public Action<string, string> DoSomething;
}
class Bar
{
public Bar()
{
Foo f1 = new Foo();
f1.DoSomething = (s) => { Console.Write(s) };
Foo f2 = new Foo();
f2.DoSomething = (s1, s2) => { Console.Write(s1 + s2) };
f1.DoSomething("Hi");
f2.DoSomething("Hi","World");
}
}
The answer seems to be no, so what is the proper way to implement something like that? (The actual problem this was trying to solve has been solved a different way, this is just curiosity at this point)
A delegate
is an abstraction of a single method (of course, several methods with similar signatures can be represented by a single delegate but from the caller's perspective, it behaves just like a single method, so that's irrelevant here.) It doesn't make sense for a single method to have multiple signatures. Hence, a delegate instance has a specific signature. Overload resolution does not have any meaning for delegates. It's not a method group you're choosing from. You're directly pointing to a method and saying "call this."
What's the solution to this problem?
It's not clear to me what the actual problem is. This might be what you're looking for:
class Foo {
public Action<string> DoSomethingDelegate1;
public Action<string,string> DoSomethingDelegate2;
public void DoSomething(string s) { DoSomethingDelegate1(s); }
public void DoSomething(string s, string t) { DoSomethingDelegate2(s, t); }
}
class Bar
{
public Bar()
{
Foo f1 = new Foo();
f1.DoSomethingDelegate1 = (s) => { Console.Write(s) };
Foo f2 = new Foo();
f2.DoSomethingDelegate2 = (s1, s2) => { Console.Write(s1 + s2) };
f1.DoSomething("Hi");
f2.DoSomething("Hi","World");
}
}
The Delegate
type is abstract and only delegates based on fully typed signatures can be created. Thus it is impossible to just create a delegate to any method without providing a Delegate
template, but it is still possible to assign using an existing delegate type, such as Action
or Action<T>
:
class Foo
{
public Delegate Target { get; set; }
public void Fire()
{
if (Target != null)
{
var pinfos = Target.Method.GetParameters();
object[] args = new object[pinfos.Length];
for (int i = 0; i < pinfos.Length; i++)
{
// Attempt to create default instance of argument:
args[i] = Activator.CreateInstance(pinfos[i].ParameterType);
}
Target.DynamicInvoke(args);
}
}
}
class Bar
{
public void Huppalupp()
{
Foo f = new Foo();
f.Target = new Action(MethodThatTakesNothing);
f.Fire();
f.Target = new Action<string>(MethodThatTakesAString);
}
void MethodThatTakesNothing()
{
Console.WriteLine("Absolutely nothing.");
}
void MethodThatTakesAString(string s)
{
Console.WriteLine(s);
}
}
This compiles, but I haven't tried it for any purposeful purpose.