I would like to have a method where the parameter could be Int32 or Single:
void myMethod( ref object x )
{
//...CodeHere
}
Since C# does not allow me to pass a specialization of object when using out or ref, the solution I found claimed that assigning the variable to a variable of the type object would be enough:
Single s = 1.0F;
object o = s;
myMethod( ref o );
That didn't work. According to the Microsoft documentation I looked at, o should be a pointer to s. The sources I looked at state that assigning non-primitive types generate a reference and not a new instance.
Is it possible to have a method where I can pass Single or Int32 or any other type that is a specialization of object?
Overload the method:
void myMethod( ref int x )
{
//...
}
void myMethod(ref single x)
{
//...
}
Unfortunately, you're out of luck. You'll be better off using two methods:
void MyMethod(ref float x)
{
//....
}
void MyMethod(ref int x)
{
//....
}
"I would like to have a method where the parameter could be Int32 or Single"
How about using a Generic method instead?
NB: In the current version of C# you can only be able to constrain the allowable types to struct not specific types such as int, float.
Instead of boxing the value in an object, you could overload the function:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
}
static int test = 0;
static void MyMethod(int arg)
{
test += arg;
}
static void MyMethod(ref int arg)
{
test += arg;
}
static void MyMethod(Single arg)
{
test += Convert.ToInt32(arg);
}
static void MyMethod(ref Single arg)
{
test += Convert.ToInt32(arg);
}
}
}
What you do with the argument inside the methods is dependent on what you're trying to accomplish, of course.
I would probably use Ash's approach and go with a generic implementation along the following lines:
static void myMethod<T>(ref T value) where T : struct, IConvertible, IComparable<T>, IEquatable<T>
{
value = (T)Convert.ChangeType(value.ToSingle(CultureInfo.CurrentCulture) * 2.0, typeof(T));
}
static void Main(string[] args)
{
int data1 = 5;
myMethod(ref data1);
if (data1 != 10)
throw new InvalidOperationException();
Single data2 = 1.5f;
myMethod(ref data2);
if (data2 != 3)
throw new InvalidOperationException();
}
Related
I'm reading, "C# in a Nutshell" and i arrived to Advanced C# features first topic: delegates.
This simple code Works
using System;
namespace prueba
{
class Program
{
public delegate int Transformer(int x);
static void Main(string[] args)
{
Transformer t = Square;
t += Cube;
int result = t(3);
Transform(5, Square);
Console.WriteLine(result);
Console.Read();
}
static int Square(int x) => x * x;
static int Cube(int x) => x * x * x;
public static void Transform(int x, Transformer t){
t(x);
}
}
} //prints => 27
When i try to use generics using this code
using System;
namespace prueba
{
class Program
{
public delegate int Transformer<T>(T arg);
static void Main(string[] args)
{
Transformer t = Square; // Compilation Error at this lane
t += Cube;
int result = t(3);
Transform(5, Square);
Console.WriteLine(result);
Console.Read();
}
static int Square(int x)
{
Console.WriteLine(x);
return 0;
}
static int Cube(int x) => x * x * x;
public static void Transform<T>(T x, Transformer<T> t){
t(x);
}
}
}
I Can't compile:
I'm really new to this and i don't get what means that i require 1 type argument, when that the only thing i did is to change the int type delegate for a generic one (T). Could someone help me?
As the error message states, you're trying to use the generic type Transformer<T> without specifying any/all the generic arguments.
This is not allowed.
Your line of code will have to specify the T you want to use:
Transformer<int> t = Square;
This means that your variable type requires a type argument when you define it:
Transformer<int> t = Square;
On the other hand, are you sure that you need to use a generic method here? Or will the delegate take other type of arguments besides int?
i have a question on reflection in c sharp..this is my question
1) define class MyClass with different fields with different accessors(private, public, protected) also methods with different argument set and return types
2) define MyTestClass which contains method, that do the following: print method names for spicified class name, where methods contain string arguments, class name is string value. Call some method of class, and put arguments to method, arguments should read from text file(name of class and name of method is arguments of method
i have answered the question but i am having a problem,i can not read from the text file when i run the program inside the text file there is a double number and an integer but its not showing on the console
this is my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.IO;
class MyClass
{
private int i;
public double d;
private string s;
public bool b;
public MyClass()
{
i = 1;
d = 0.1;
s = "1";
b = true;
}
public void Method0()
{
Console.WriteLine("Method with no arguments, no return value.");
}
private int Method1(int arg0)
{
Console.WriteLine("The method returns int, int gets.");
return arg0;
}
private double Method2(int arg0, double arg1)
{
Console.WriteLine("Method returns a double, taking int and double.");
return arg1 * arg0;
}
public bool Method3(string arg0)
{
Console.WriteLine("Method returns a bool, accepts string");
return arg0.Length>10;
}
public bool Method3(string arg0,string arg1)
{
Console.WriteLine("The method takes two arguments string.");
return arg0 == arg1;
}
public static char Method4(string arg0)
{
Console.WriteLine("Method returns a char, accepts string. .");
return arg0[1];
}
public void Method5(int arg0, double arg1)
{
Console.WriteLine("arg1 = {0} arg2 = {1}.",arg0,arg1);
}
}
class MyTestClass
{
public static string[] GetMethodsWithStrParams(string className)
{
var t = Type.GetType(className);
List<string> res = new List<string>();
foreach (var method in t.GetMethods())
{
foreach (var param in method.GetParameters())
{
if (param.ParameterType == typeof(string))
{
res.Add(method.Name);
break;
}
}
}
return res.ToArray();
}
public static void InvokeMethod(string className, string methodName, string fileName)
{
var t = Type.GetType(className);
using (StreamReader f = new StreamReader("params.txt"))
{
t.GetMethod(methodName).Invoke(t.GetConstructor(Type.EmptyTypes).Invoke(new object[] { }),
new object[] { f.ReadLine() });
}
}
}
class Program
{
static void Main(string[] args)
{
string name = "MyClass";
foreach (var x in MyTestClass.GetMethodsWithStrParams(name))
{
Console.WriteLine(x);
}
MyTestClass.InvokeMethod("MyClass", "Method4", "params.txt");
Console.ReadKey(true);
}
}
this is the output when i run the program
method3
method3
method4
Method returns a char, accepts string. .
but inside params.txt there is
10 1.5
Some suggestions:
Split the reflection part into two: 1) the construction of the object; 2) the invoke of the method. This makes the code a bit clearer and you could maybe re-use the object for the invoke of a next method.
The f.ReadLine() returns a single string. It does not automatically split this into separate arguments. The new object[] { f.ReadLine() } gives an object-array with a single string value.
You will need to split that line yourself on some separator into separate values. Then you will need to convert those separate strings into the parameter-types your method needs.
I run your code in visual Studio and the only problem I had was the file name. the rest seemed to work in principle. is the file params.txt definitely in executable folder? If not you will need to provide full path.
MyTestClass.InvokeMethod("MyClass", "Method4", "c:\\params.txt");
Another question I have is? does MyClass exist within a namespace? If so you will need to use namespace to return Type object:
MyTestClass.InvokeMethod("MyNamespace.MyClass", "Method4", "c:\\params.txt");
Also I just noticed that despite the fact that method InvokeMethod accepts filename as argument it has got a hard-coded filename. It therefore ignores filename passed by calling code (in main method).
I have heard/read the term but don't quite understand what it means.
When should I use this technique and how would I use it? Can anyone provide a good code sample?
The visitor pattern is a way of doing double-dispatch in an object-oriented way.
It's useful for when you want to choose which method to use for a given argument based on its type at runtime rather than compile time.
Double dispatch is a special case of multiple dispatch.
When you call a virtual method on an object, that's considered single-dispatch because which actual method is called depends on the type of the single object.
For double dispatch, both the object's type and the method sole argument's type is taken into account. This is like method overload resolution, except that the argument type is determined at runtime in double-dispatch instead of statically at compile-time.
In multiple-dispatch, a method can have multiple arguments passed to it and which implementation is used depends on each argument's type. The order that the types are evaluated depends on the language. In LISP, it checks each type from first to last.
Languages with multiple dispatch make use of generic functions, which are just function delcarations and aren't like generic methods, which use type parameters.
To do double-dispatch in C#, you can declare a method with a sole object argument and then specific methods with specific types:
using System.Linq;
class DoubleDispatch
{
public T Foo<T>(object arg)
{
var method = from m in GetType().GetMethods()
where m.Name == "Foo"
&& m.GetParameters().Length==1
&& arg.GetType().IsAssignableFrom
(m.GetParameters()[0].GetType())
&& m.ReturnType == typeof(T)
select m;
return (T) method.Single().Invoke(this,new object[]{arg});
}
public int Foo(int arg) { /* ... */ }
static void Test()
{
object x = 5;
Foo<int>(x); //should call Foo(int) via Foo<T>(object).
}
}
The code posted by Mark isn't complete and what ever is there isn't working.
So tweaked and complete.
class DoubleDispatch
{
public T Foo<T>(object arg)
{
var method = from m in GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
where m.Name == "Foo"
&& m.GetParameters().Length == 1
//&& arg.GetType().IsAssignableFrom
// (m.GetParameters()[0].GetType())
&&Type.GetType(m.GetParameters()[0].ParameterType.FullName).IsAssignableFrom(arg.GetType())
&& m.ReturnType == typeof(T)
select m;
return (T)method.Single().Invoke(this, new object[] { arg });
}
public int Foo(int arg)
{
return 10;
}
public string Foo(string arg)
{
return 5.ToString();
}
public static void Main(string[] args)
{
object x = 5;
DoubleDispatch dispatch = new DoubleDispatch();
Console.WriteLine(dispatch.Foo<int>(x));
Console.WriteLine(dispatch.Foo<string>(x.ToString()));
Console.ReadLine();
}
}
Thanks Mark and others for nice explanation on Double Dispatcher pattern.
C# 4 introduces the pseudo type dynamic which resolves the function call at runtime (instead of compile time). (That is, the runtime type of the expression is used). Double- (or multi-dispatch) can be simplified to:
class C { }
static void Foo(C x) => Console.WriteLine(nameof(Foo));
static void Foo(object x) => Console.WriteLine(nameof(Object));
public static void Main(string[] args)
{
object x = new C();
Foo((dynamic)x); // prints: "Foo"
Foo(x); // prints: "Object"
}
Note also by using dynamic you prevent the static analyzer of the compiler to examine this part of the code. You should therefore carefully consider the use of dynamic.
The other answers use generics and the runtime type system. But to be clear the use of generics and runtime type system doesn't have anything to do with double dispatch. They can be used to implement it but double dispatch is just dependent on using the concrete type at runtime to dispatch calls. It's illustrated more clearly I think in the wikipedia page. I'll include the translated C++ code below. The key to this is the virtual CollideWith on SpaceShip and that it's overridden on ApolloSpacecraft. This is where the "double" dispatch takes place and the correct asteroid method is called for the given spaceship type.
class SpaceShip
{
public virtual void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class ApolloSpacecraft : SpaceShip
{
public override void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class Asteroid
{
public virtual void CollideWith(SpaceShip target)
{
Console.WriteLine("Asteroid hit a SpaceShip");
}
public virtual void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("Asteroid hit ApolloSpacecraft");
}
}
class ExplodingAsteroid : Asteroid
{
public override void CollideWith(SpaceShip target)
{
Console.WriteLine("ExplodingAsteroid hit a SpaceShip");
}
public override void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("ExplodingAsteroid hit ApolloSpacecraft");
}
}
class Program
{
static void Main(string[] args)
{
Asteroid[] asteroids = new Asteroid[] { new Asteroid(), new ExplodingAsteroid() };
ApolloSpacecraft spacecraft = new ApolloSpacecraft();
spacecraft.CollideWith(asteroids[0]);
spacecraft.CollideWith(asteroids[1]);
SpaceShip spaceShip = new SpaceShip();
spaceShip.CollideWith(asteroids[0]);
spaceShip.CollideWith(asteroids[1]);
}
}
Full listing of working code
using System;
using System.Linq;
namespace TestConsoleApp
{
internal class Program
{
public static void Main(string[] args)
{
const int x = 5;
var dispatch = new DoubleDispatch();
Console.WriteLine(dispatch.Foo<int>(x));
Console.WriteLine(dispatch.Foo<string>(x.ToString()));
Console.ReadLine();
}
}
public class DoubleDispatch
{
public T Foo<T>(T arg)
{
var method = GetType()
.GetMethods()
.Single(m =>
m.Name == "Foo" &&
m.GetParameters().Length == 1 &&
arg.GetType().IsAssignableFrom(m.GetParameters()[0].ParameterType) &&
m.ReturnType == typeof(T));
return (T) method.Invoke(this, new object[] {arg});
}
public int Foo(int arg)
{
return arg;
}
public string Foo(string arg)
{
return arg;
}
}
}
I have a lot of functions which are currently overloaded to operate on int and string:
bool foo(int);
bool foo(string);
bool bar(int);
bool bar(string);
void baz(int p);
void baz(string p);
I then have a lot of functions taking 1, 2, 3, or 4 arguments of either int or string, which call the aforementioned functions:
void g(int p1) { if(foo(p1)) baz(p1); }
void g(string p1) { if(foo(p1)) baz(p1); }
void g(int p2, int p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(int p2, string p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(string p2, int p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(string p2, string p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
// etc.
Note: The implementation of the g() family is just an example
More types than the current int or string might be introduced at any time. The same goes for functions with more arguments than 4. The current number of identical functions is barely manageable. Add one more variant in either dimension and the combinatoric explosion will be so huge, it might blow away the application.
In C++, I'd templatize g() and be done.
I understand that .NET generics are different. I have been fighting them for two hours now trying to come up with a solution that doesn't involve copy and pasting code, to no avail.
C# generics won't require me to type out identical code for a family of functions taking five arguments of either of three types?
What am I missing?
Edit: These functions are used to parse a bunch of arguments (currently either int or string) from some source. Imagine bar() and baz() being able to read both int or string, and the g() family specifying the type and number of arguments to parse (implicitly, by their arguments' types).
Consider using inheritance for this case. I am assuming that foo, bar and baz are inherent to the type (int or string in your case). If this is not true please correct or comment this answer.
using System;
namespace ConsoleApplication3
{
abstract class Param
{
public abstract bool Foo();
public abstract bool Bar();
public abstract void Baz();
public static IntParam Create(int value)
{
return new IntParam(value);
}
public static StringParam Create(string value)
{
return new StringParam(value);
}
}
abstract class Param<T> : Param {
private T value;
protected Param() { }
protected Param(T value) { this.value = value; }
public T Value {
get { return this.value; }
set { this.value = value; }
}
}
class IntParam : Param<int>
{
public IntParam() { }
public IntParam(int value) : base(value) { }
public override bool Foo() { return true; }
public override bool Bar() { return true; }
public override void Baz()
{
Console.WriteLine("int param value is " + this.Value);
}
}
class StringParam : Param<string>
{
public StringParam() { }
public StringParam(string value) : base(value) { }
public override bool Foo() { return true; }
public override bool Bar() { return true; }
public override void Baz()
{
Console.WriteLine("String param value is " + this.Value);
}
}
class Program
{
static void g(Param p1)
{
if (p1.Foo()) { p1.Baz(); }
}
static void g(Param p1, Param p2)
{
if (p1.Foo()) { p1.Baz(); }
if (p2.Bar()) { p2.Baz(); }
}
static void Main(string[] args)
{
Param p1 = Param.Create(12);
Param p2 = Param.Create("viva");
g(p1);
g(p2);
g(p1, p1);
g(p1, p2);
g(p2, p1);
g(p2, p2);
Console.ReadKey();
}
}
}
This would output:
int param value is 12
String param value is viva
int param value is 12
int param value is 12
int param value is 12
String param value is viva
String param value is viva
int param value is 12
String param value is viva
String param value is viva
For a new supported type you:
create a new class that supports the type and extends Param<T>;
implement Foo, Bar and Baz for that new type;
Create a new g method (just one) that has another parameter.
Specially for 3) this would greatly reduce explosion of methods. Now you write a single g method for any given number of parameters. With previous design you had to write, for n parameters, 2^n methods (n = 1 -> 2 methods, n = 2 -> 4 methods, n = 3 -> 8 methods, ..).
Your true problem here is most likely one of design, rather than something generics can be used for. Generics should be used for things that are actually type-agnostic, not as a catch-all to make life a bit easier. Perhaps try posting some actual example code you're using, and someone may have an idea about how to redesign your solution in a way that will allow you to extend it without so much headache.
As a teaser, consider something like this:
public void DoSomethingConditionally<T>(T key, Func<T, bool> BooleanCheck, Action<T> WhatToDo)
{
if (BooleanCheck(key)) WhatToDo(key);
}
And you could call it like this:
DoSomethingConditionally<String>("input", v => v == "hello", s => Console.WriteLine(s));
I've used lambda expressions here, but you could just as easily predefine a few Func<>s that perform some common expressions. This would be a much better pattern than method overloading, and would force you to handle new input types at design time.
Not as optimal as I would like... but what if foo, bar, and baz had generic versions as well?
static bool foo(int input)
{
return input > 5;
}
static bool foo(string input)
{
return input.Length > 5;
}
static void baz(int input)
{
Console.WriteLine(input);
}
static void baz(string input)
{
Console.WriteLine(input);
}
static bool foo<T>(T input)
{
if (input is int) return foo((int)(object)input);
if (input is string) return foo((string)(object)input);
return false;
}
static void baz<T>(T input)
{
if (input is int) baz((int)(object)input);
else if (input is string) baz((string)(object)input);
else throw new NotImplementedException();
}
static void g<T>(T input)
{
if (foo(input))
baz(input);
}
static void g<T, U>(T input, U inputU)
{
g(input);
g(inputU);
}
Use a list of objects.
In the case the number of parameters are unknown at planning time, just use a list of objects. Something like:
void g(params object[] args) {
foreach (object arg in args) {
if ((arg is int) && (foo((int)arg))) baz((int)arg) else
if ((arg is string) && (foo((string)arg))) baz((string)arg)
}
}
(Assuming you have bool foo(int), bool foo(string)...)
So you can call:
g(p1, p2);
g(p1);
g(p1, p2, p3)
with any combination of the types, since every reference derives from object (which it could be many more types than required, int and string, but could be handy in future to support more other types).
This is possible since you could use Reflection to recognize the type at runtime.
Another way to execute a sequence of operation is the use of interfaces, defining the action to execute at certain conditions, on certain objects.
interface IUpdatable {
void Update(object[] data);
}
class object1 : IUpdatable { public void Update(object data) { baz(data); } }
class object2 : IUpdatable { public void Update(object data) { baz(data); } }
void g(params IUpdatable[] args) {
foreach (IUpdatable arg in args) {
arg.Update(args);
}
}
But this way you have to model p1 and p2 (but also p3, as objects implementing an interface, which could be not possible.
I would have done this as a comment to #smink, but I don't have enough rep...
If you extend the Param base class to have implicit operators you are back to not having to wrap the contents in code (though the runtime still incurs the wrapping overhead)...
abstract class Param
{
...
public static implicit operator Param(int value)
{ return new IntParam(value); }
}
If you are using C# / .NET 4.0, you can achieve multiple dispatch using the dynamic feature so you only have to implement a single overload of g based on the number of arguments and the proper foo/bar/baz overloads by type inside each g implementation will be resolved at runtime.
void g(dynamic p1) { if (foo(p1)) baz(p1); }
void g(dynamic p1, dynamic p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }
Edit:
Even though you are unable to use C# / .NET 4.0, you can still use this approach using reflection. I've added another foo/bar/baz overload for double showing how well this generalizes and allows you to eliminate duplicate g implementations.
bool foo(int p) {Console.WriteLine("foo(int)=" + p); return p == 0;}
bool foo(string p) {Console.WriteLine("foo(string)=" + p); return p == "";}
bool foo(double p) { Console.WriteLine("foo(double)=" + p); return p == 0.0; }
bool bar(int p) {Console.WriteLine("bar(int)=" + p); return p == 1;}
bool bar(string p) { Console.WriteLine("bar(string)=" + p); return p == ""; }
bool bar(double p) { Console.WriteLine("bar(double)=" + p); return p == 1.1; }
void baz(int p) {Console.WriteLine("baz(int)=" + p);}
void baz(string p) { Console.WriteLine("baz(string)=" + p); }
void baz(double p) { Console.WriteLine("baz(double)=" + p); }
//these object overloads of foo/bar/baz allow runtime overload resolution
bool foo(object p)
{
if(p == null) //we need the type info from an instance
throw new ArgumentNullException();
//may memoize MethodInfo by type of p
MethodInfo mi = typeof(Program).GetMethod(
"foo",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
return (bool)mi.Invoke(this, new object[] { p });
}
bool bar(object p)
{
if (p == null)
throw new ArgumentNullException();
MethodInfo mi = typeof(Program).GetMethod(
"bar",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
return (bool)mi.Invoke(this, new object[] { p });
}
void baz(object p)
{
if (p == null)
throw new ArgumentNullException();
MethodInfo mi = typeof(Program).GetMethod(
"baz",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
mi.Invoke(this, new object[] { p });
}
//now you don't need to enumerate your identical implementations of g by type
void g(object p1) { if (foo(p1)) baz(p1); }
void g(object p1, object p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }
Unfortunately, generics cannot handle this situation. At least, not well. If you make your methods generic, then just about any type can be passed into them. There won't be an adequate where clause on the generics to limit it to just string and int. If your methods are going to do specific int/string related operations inside them, then generics wont work at all.
Generics in C# are not nearly as powerful as templates in C++, and yes they can cause some major headaches at time. It just takes time to get used to them and get a feel for what they can and cannot do.
This might be a bit heavy handed, but would encapsulating the different parameters types as classes work?:
public abstract class BaseStuff
{
public abstract bool Foo();
public abstract bool Bar();
public abstract void Baz();
public void FooBaz()
{
if(Foo()) Baz();
}
public void BarBaz()
{
if(Bar()) Baz();
}
}
public class IntStuff : BaseStuff
{
private int input;
public IntStuff(int input)
{
this.input = input;
}
public bool Foo()
{
//logic using input for example
return input > 0;
}
//implement Bar and Baz using input
}
public class StringStuff : BaseStuff
{
private string input;
public IntStuff(string input)
{
this.input = input;
}
//Implement Foo, Bar and Baz
}
And then have some G methods somewhere:
public void G(BaseStuff stuff1)
{
stuff1.FooBaz();
}
public void G(BaseStuff stuff1, BaseStuff stuff2)
{
stuff1.FooBaz();
stuff2.BarBaz();
}
And you can then call with:
G(new IntStuff(10), new StringStuff("hello"));
G(new StringStuff("hello"), new StringStuff("world"));
You can use code generation to solve this.
Look at Reflection.Emit. You can also generate code with T4 in Visual Studio.
The types are really getting in the way here. You could also try to solve this with a dynamic language or with the C# 4 dynamic keyword.
If you are using c# 4.0 you can do this with the option parameter
Or you can use object
Foo(object o)
{
if (o is int){ }
else if (o is string){ }
}
Or you can use the generic method Foo<T>(T o){ }
Is it possible to pass a function as a parameter in C#? I can do it using the Func or Action classes, but this forces me to declare the entire function signature at once. When I try to use Delegate, I get a compile error saying it can't convert a method group to a Delegate.
I'm working on Axial and I'm trying to allow users to call web services. What I'm going for is the ability to create the Visual Studio proxy class and then pass in the generated function. The function signature doesn't matter because the generated code only uses the function name. However, I'd like to pass in the function instead of the name for two reasons: the ability to use the proxy's Url property and a compiler error if the web service doesn't exist or is updated in Visual Studio.
public void AlertIt(object o) {
Axial.DOM.Window.Alert(o.ToString());
}
public void CallAddService() {
object[] param = new object[] { int.Parse(txtA.Text), int.Parse(txtB.Text) };
Axial.ServerScript.CallWebService(new WSProxy.WS().Add, param, AlertIt, AlertIt);
}
class Axial.ServerScript {
public void CallWebService(Delegate method, object[] param, Action<object> successCallback, Action<object> failureCallback) {
// translate to javascript (already working)
}
}
I think what you want is:
static object InvokeMethod(Delegate method, params object[] args){
return method.DynamicInvoke(args);
}
static int Add(int a, int b){
return a + b;
}
static void Test(){
Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}
Prints "9".
Converting a method group, anonymous method or lambda expression to a delegate requires the compiler to know the exact delegate type. However, you could potentially use lambda expressions and captured variables to make this simpler:
public void InvokeMethod(Action action)
{
action();
}
public int Add(int a, int b)
{
return a + b;
}
public void Test()
{
InvokeMethod(() => Add(2, 3));
}
That basically delays invocation in the normal way, but by wrapping the actual call to Add in a plain Action delegate.
If that doesn't fulfil your requirements, perhaps you can tell us a bit more about what you're really trying to achieve.
EDIT: If this is generated code, you can cast to a Func<...> with the right type arguments - assuming there aren't too many. Other than that, there's no real way of just passing in a method group. There's been occasional calls for an "infoof(...)" operator (like typeof but for members) which would give you a MemberInfo, but that doesn't actually exist.
You should have a delegate first
delegate int Operation(int a, int b)
then it becomes:
public void InvokeMethod(Operation method, object target, object param)
{
method((int) target, (int) param);
}
No need for any call to Invoke.
As with dbone I'm unsure why you would need a params[] array. Would you clarify the expanded usage for the params?
Also, I'll have to correct something in your question though, because it will cause a compilation error :p
please have a look at using delegates here is a great example
Delegate Example
why are you using reflection? will there ever be a different number of params? or do you know the method signture will remain constant (also remember C# supports the params[] keyword)
params c#
HTH
Bones
Look at Functional Programming Series by Justin Etheredge.
You should find solution to your problem there.
This is much simple example, to programmer who already familiar with (C/C++/VB.NET/Python)-style pass function by pointer/ref (with C# delegate):
delegate void CALLBACK(String s);
static void Main(string[] args)
{
Get("some string", testfunc);
Util.pause();
}
static void Get(String s, CALLBACK x)
{
x(s);
}
static void testfunc(String s)
{
Console.WriteLine(s);
}
Say If you need to pass the method as parameter as well as you need to catch the return value for further processing . Then the above examples will work fine .
But say if you need to pass a method with void return type then you need to create one more version of the InvokeMethod function.
Check the example below.
private static T retry<T>(Delegate method, params object[] args)
{
for (int i = 0; i <= 3; i++)
{
try
{
return (T)method.DynamicInvoke(args);
}
catch (Exception ex)
{
if (i == 3)
{
logMessage(ex.Message);
}
Console.WriteLine("Retry count " + i);
Thread.Sleep(10);
}
}
return default(T);
}
private static void retry2(Delegate method, params object[] args)
{
for (int i = 0; i <= 3; i++)
{
try
{
method.DynamicInvoke(args);
break;
}
catch (Exception ex)
{
if (i == 3)
{
logMessage(ex.Message);
//return default(T);
}
Console.WriteLine("Retry count " + i);
Thread.Sleep(10);
}
}
}
static bool isSuccess = true;
static void logMessage(string msg)
{
isSuccess = false;
Console.WriteLine(msg);
}
static int Add(int a, int b)
{
return a + b;
}
static void Add2(int a, int b)
{
int c = a + b;
Console.WriteLine(c);
}
static void Main(string[] args)
{
int d = retry<int>(new Func<int, int, int>(Add), 6, 7.7);
Console.Write(" " + d + "\n"+isSuccess);
retry2(new Action<int, int>(Add2), 45, 60);
Console.ReadKey();
}
Something like this ought to work for you:
delegate int MyDelegate(int a, int b);
public int Add(int a, int b) {
return a + b;
}
public void InvokeMethod(Delegate method, object[] param) {
Console.WriteLine(method.DynamicInvoke(param));
}
public Form1() {
InitializeComponent();
InvokeMethod(new MyDelegate(Add), new object[] { 1, 2 });
}
Good luck!