Reputation: 144
I have a delegate expecting parameters of type A as parameters. So A is the base class. Class B and C inherit from A.
The problem is that although B and C inherit from the base class A, the DoSomething functions at the bottom of the script can't be converted to the delegate.
public class A { }
public class B : A { }
public class C : A { }
public delegate void CallbackAction(params A[] paremeters);
public class Main
{
public int main(params string[] args)
{
CallbackAction callbackAction;
callbackAction = DoSomething1;
callbackAction = DoSomething2;
callbackAction = DoSomething3;
return 0;
}
public void DoSomething1(A arg0) { }
public void DoSomething2(B arg0) { }
public void DoSomething3(C arg0) { }
}
Is there any way to use params in a delegate and be able to use classes that have the params class as their base class?
When compiling the error I get is: Error 5 No overload for 'DoSomething3' matches delegate 'SKConsole.CallbackAction'
I'm using .NET 4 and XNA
EDIT:: Ok let me explain why I am using this I am creating a console. This means a programmer using my console can add a command (console.AddCommand("help", Help) to the console, Help here is a function. When you are ingame and typing help in the console it will execute the function Help(). I now want it to work with console.AddCommand("setSpeed", SetPlayerSpeed) aswell. The SetPlayerSpeed function has 1 parameter, an int. But I want it to work with any function so if a programmer creates the function DoSomeFancyStuff(float a, string b, int c) I want the console to create a command and if you type in the correct string in the console execute these command.
I already tried making lots of delegates for different functions, but this is kinda ugly in my opinion.
What I then tried was the following
public abstract class SKConsoleParameter
{
protected string value;
public SKConsoleParameter(string value)
{
this.value = value;
}
public string GetRawValue()
{
return value;
}
public abstract bool IsValid();
public abstract object GetValue();
}
public class StringParam : SKConsoleParameter
{
public StringParam(string value) : base(value) { }
public override bool IsValid()
{
return true;
}
public override object GetValue()
{
return value;
}
}
public class IntParam : SKConsoleParameter
{
public IntParam(string value) : base(value) { }
public override bool IsValid()
{
int i;
return int.TryParse(value, out i);
}
public override object GetValue()
{
int i;
if (int.TryParse(value, out i))
return i;
else
return 0;
}
}
Was this does is that if a developer creates a function like:
DoSomethingCool(StringParam s, IntParam i)
Then it can receive the values by using (string)s.GetValue() and (int)i.GetValue() The StringParam and IntParam classes both inherit from SKConsoleParameter, so i though I could now create the follwoing delegate
void CoolDelegate(params SKConsoleParameter[] parameters)
But this doesn't work.. Because of the abstract problem with class A, B and C at the top of this page
Does anyone have any ideas to counter this problem?
Upvotes: 1
Views: 1206
Reputation: 10390
based on your updated code -- try this. As long as your method matches the delegate the contravariance should work as expected in .NET 3.5 or better
public abstract class SKConsoleParameter
{
protected string value;
public SKConsoleParameter(string value)
{
this.value = value;
}
public string GetRawValue()
{
return value;
}
public abstract bool IsValid();
public abstract object GetValue();
}
public class StringParam : SKConsoleParameter
{
public StringParam(string value) : base(value) { }
public override bool IsValid()
{
return true;
}
public override object GetValue()
{
return value;
}
}
public class IntParam : SKConsoleParameter
{
public IntParam(string value) : base(value) { }
public override bool IsValid()
{
int i;
return int.TryParse(value, out i);
}
public override object GetValue()
{
int i;
if (int.TryParse(value, out i))
return i;
else
return 0;
}
}
class Program
{
public delegate void CoolDelegate(params SKConsoleParameter[] parameters);
static void Main(string[] args)
{
var s = new StringParam("Glenn");
var i = new IntParam("12");
var coolDel = new CoolDelegate(DoSomethingCool);
coolDel(s, i);
}
public static void DoSomethingCool(params SKConsoleParameter[] parameters)
{
if (parameters == null) throw new ArgumentNullException("parameters");
foreach (var item in parameters)
{
if (item is IntParam)
{
// do something interesting
continue;
}
if (item is StringParam)
{
// do something else interesting
continue;
}
throw new NotImplementedException("unknown param type");
}
}
}
Upvotes: 0
Reputation: 20066
You are looking for the error in the wrong place. C# allows contravariance in delegates' input parameters. The problem with your code is that your delegate takes params A[]
, while your method takes a single A
. This is not allowed. Delcare your delegate as accepting a single A
:
delegate void Callback1 (B a) ;
void Test11 (A a) {}
void Test12 (B b) {}
Callback1 c11 = Test11 ; // OK
Callback1 c12 = Test12 ; // OK
Note also that this does not work with array parameters:
delegate void Callback2 (B[] a) ;
void Test21 (A[] a) {}
void Test22 (B[] b) {}
Callback2 c21 = Test21 ; // compile error
Callback2 c22 = Test22 ; // OK
Upvotes: 1
Reputation: 10390
Try this code:
public class A { }
public class B : A { }
public class C : A { }
public static class Helper
{
public static Action<A> DoSomething;
}
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
var c = new C();
Helper.DoSomething = new Action<A>(DoSomething1);
Helper.DoSomething = (Action<A>)new Action<B>(DoSomething2);
Helper.DoSomething = (Action<A>)new Action<C>(DoSomething3);
}
public static void DoSomething1(A a) { }
public static void DoSomething2(B a) { }
public static void DoSomething3(C a) { }
}
Upvotes: 0