This question already has answers here:
Optional delegates in C# [duplicate]
(4 answers)
Closed 9 years ago.
I need to call a delegate method passed as a parameter, but since this parameter is optional I want to set the default value to a method implemented in the "destination" class.
This is an example where it almost works as expected:
public class AgeCalculator
{
public void SetAge(Client client, Func<int, int> getAge = default(Func<int, int>))
{
client.Age = getAge != default(Func<int, int>) ? getAge(client.Id) : this.getAge(client.Id);
}
private int getAge(int clientId) {
return 10;
}
}
And then..
class Program
{
static void Main(string[] args)
{
AgeCalculator calculator = new AgeCalculator();
Client cli1 = new Client(1, "theOne");
calculator.SetAge(cli1);//Sets 10
calculator.SetAge(cli1, getAge);//Sets 5
}
private static int getAge(int clientId) {
return 5;
}
}
The question now; what is the default value that has to be setted to avoid asking about the delegate value?
Tried "public void SetAge(Client client, Func getAge = this.getAge)" with no luck.
Is there a tag or different definition needed on AgeCalculator.getAge?, should I use dynamic methods?
Thanks in advance.
Note: The real scenario involves more complex logic in a TDD oriented project, this is a sample to summarize the situation.
Default values for method arguments must be compile-time constants. Writing default(Func<...>) is just verbose syntax for null, which is the default value for reference types (as a delegate, Func is a reference type) and the only default value you can use in this context.
However, you can do much better with the old-fashioned way of offering two overloads for the method:
public void SetAge(Client client)
{
// Select any default value you want by calling the other overload with it
SetAge(client, this.getAge);
}
public void SetAge(Client client, Func<int, int> getAge)
{
client.Age = getAge(client.Id);
}
This is basically doing what you are asking, the only thing is that the hints given by VS won't show that a function is being used as the default if null isn't used. If that isn't a problem then this solution is logically as close as you are going to get.
public class AgeCalculator
{
public void SetAge ( Client client , Func<int , int> getAge = null)
{
// assigns this.getAge to getAge if getAge is null
getAge = getAge ?? this.getAge;
client.Age = getAge( client.Id );
}
private int getAge ( int clientId )
{
return 10;
}
}
You can also make this something that allows a variable method to be plugged in if you want to change the default setter dynamically. It is identical logic just another way, this is beneficial if you know you will use the same function multiple times in a row.
public class AgeCalculator
{
public void SetAge ( Client client )
{
client.Age = GetAge( client.Id );
}
private Func<int,int> _getAge;
public Func<int,int> GetAge
{
private get
{
if(_getAge == null)
_getAge = getAge;
return _getAge;
}
set
{
if(value == null)
_getAge = getAge;
else
_getAge = value;
}
}
private int getAge ( int clientId )
{
return 10;
}
}
//assume we are in main
var cl = new Agecalculator();
var client = new Client(1,"theOne");
var client2 = new Client(2,"#2");
cl.SetAge(client); //set 10
cl.GetAge = getAge;
cl.SetAge(client); //set 5
cl.SetAge(client2); //set 5
Related
Is there a way to get rid of the CS0411 error below, and not have to explicitly state the type?
Also do not want to have to use reflection.
var router = new ExampleRouter();
var controller = new ExampleWebController();
// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);
// error CS0411: can't infer type
router.MapPost("/api/foo", controller.ProcessString);
class ExampleWebController {
public ExampleWebController() { }
public bool ProcessNumber(int v) { return true; }
public bool ProcessString(string v) { return true; }
}
class ExampleRouter {
public ExampleRouter() { }
public void MapPost<TBody>(string path, Func<TBody, bool> handler) {
// Save typeof(TBody), since TBody will actually be a class type we
// will construct for each callback
var body_type = typeof(TBody);
}
}
Yep, as someone's mentioned in comments one solution is to pass in the data as a parameter:
public void MapPost<TBody>(string path, Func<TBody, bool> handler, Tbody data) {
object dataType = data.GetType();
}
The reason your code is "inelegant" as you've said, is because the order of your generic arguments specifies an input type (TBody) and an output type (bool). However, in your calls to MapBody, you are only providing methods that return boolean results, so that the compiler doesn't know what to use for the value of TBody.
This is the origin of the CS0411 error you are receiving. The only way around it is to provide a generic type argument at the point of call.
This is why this code works, and should be what you use going forward:
var router = new ExampleRouter();
var controller = new ExampleWebController();
// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);
A bit of a self answer here. If I change it to this, the MapPost() code looks elegant, which was my goal. HOWEVER, I have lost some compile time checking -- for example anything can be passed in as a "handler". I will post a new question on how I refine this.
var router = new ExampleRouter();
var controller = new ExampleWebController();
// We will have to do runtime validation that controller.ProcessString is a
// legal callback (which isn't ideal, but still fine).
// An improvement would be to add some kind of generic constraints?
router.MapPost("/api/foo", controller.ProcessString);
class ExampleWebController {
public ExampleWebController() { }
public bool ProcessNumber(int v) { return true; }
public bool ProcessString(string v) { return true; }
}
class ExampleRouter {
public ExampleRouter() { }
public void MapPost<TFunc>(string path, TFunc handler) {
var func_type = typeof(TFunc);
Console.WriteLine(func_type); // Prints "System.Func"
var args = func_type.GetGenericArguments();
foreach (var arg in args) {
// Prints "System.String", "System.Boolean"...awesome
Console.WriteLine(arg);
}
}
}
I wonder if there is a way to use a reference of a var like 'ref' but not in a method.
exemple :
using System;
using System.Collections;
using System.Collections.Generic;
public class Class3
{
struct myStruct
{
public bool structBool;
public int structInt;
public myStruct(bool _structBool, int _structInt)
{
structBool = _structBool;
structInt = _structInt;
}
}
myStruct currentTask;
int value1,value2;
bool mybool, isProcessing;
Queue<myStruct> myTask = new Queue<myStruct>();
void main()
{
//these two lines don't work due to the "ref" but I'm looking for something work like this
if (value1 > value2) myTask.Enqueue(new myStruct(mybool,ref value1));
if (value2 > value1) myTask.Enqueue(new myStruct(mybool,ref value2));
MyFunction();
}
void MyFunction()
{
if (myTask.Count > 0)
{
if (!isProcessing)
{
currentTask = myTask.Dequeue();
isProcessing = true;
}
else
{
currentTask.structInt++; // here I need to catch my var (value1 or value2)
}
}
}
}
I tried to put the values into an array but I think it's a bad way. I tried lot of other stuff but nothing work properly.
You can change the constructor to pass those parameters by reference like so:
public myStruct(bool _structBool, ref int _structInt),
The problem is that invoking this line
currentTask.structInt++;
still wouldn't change the original variables (value1, value2). Check the solution in the answer here: https://stackoverflow.com/a/13120988/775018
Usually when you want to give multiple values to a constructor (or even a method), it's very acceptable that you give them as part of a class:
public class Args
{
public int Value { get; set; }
}
So now you can do this:
Args args1 = new Args { Value = 10 };
Args args2 = new Args { Value = 34 };
// Obviously, your structs or classes should accept Args class as input parameter
var struct1 = new MyStruct(true, args1);
var struct2 = new MyStruct(false, args2);
Now modifications to Args.Value1 and/or Args.Value2 will be available for the struct constructor callers.
I am running into a road block when I am trying to do some testing on delegate. My goal is to create instances of MyStates class that have the ability to call some predefined functions that I defined in MyFunctions class. In the class, I have a dictionary that will refer the functions by name and have a function that retrieve the address of the function and put it in MyState instance so that I could refer it at run time. The idea appears to be simple but the compiler is not happy about it. I think I may have an idea of what is wrong but I am not sure how to get rid of the compiler error. Please advise how to fix this compiler error.
MyFunctions class is defined as below:
public sealed class MyFunctions
{
public delegate int myFunction(object o);
private static Dictionary<string, myFunction> funcRouter
= new Dictionary<string, myFunction>();
#region Singleton
private static readonly MyFunctions _functionInstance = new MyFunctions();
static MyFunctions()
{
}
private MyFunctions()
{
funcRouter.Add("Test2", Test2);
}
public static MyFunctions functionInstance
{
get
{
return _functionInstance;
}
}
#endregion
#region Definition and implementation of all the functions
public int Test2(object o)
{
System.Diagnostics.Debug.WriteLine("Testing 2, object received {0}", (int)o);
return 112;
}
#endregion
public myFunction Get(string s)
{
return (myFunction)funcRouter[s];
}
}
MyStates class is defined below:
public delegate int myFunction(object o);
public class MyState
{
private int _ID;
private myFunction _func;
public myFunction func
{
get { return _func; }
}
public int ID
{
get { return _ID; }
}
public MyState(int myID, myFunction f = null)
{
_ID = myID;
_func = f;
}
}
My main program:
public delegate int myFunction(object o);
class Program
{
static void Main(string[] args)
{
myFunction f = null;
//f = MyFunctions.functionInstance.Test2;
f = MyFunctions.functionInstance.Get("Test2");
MyState s = new MyState(123,f);
Console.ReadLine();
}
}
Note: The code above will generate the compiling error. However, if I use the statement
f = MyFunctions.functionInstance.Test2;
The program will compile fine and execute correctly. I think the issue resides in the use of dictionary to retrieve the address of the function. It is possible to possible to do that in C++, I would think C# should allow me to do the same thing. I just did not do it correctly.
Please advise.
You are defining public delegate int myFunction(object o); in two places. The compiler error error says you can't convert one to the other. This is because in the case of f = MyFunctions.functionInstance.Get("Test2"); you are assigning a return value of one type to a variable of a different type, but with f = MyFunctions.functionInstance.Test2; the compiler just looks for a method signature that matches the delegate.
One fix is to declare f as MyDelegates.MyFunctions.myFunction.
MyDelegates.MyFunctions.myFunction f;
f = MyDelegates.MyFunctions.functionInstance.Get("Test2");
Another way is to wrap it in your local delegate (because then the signature-match is used again):
myFunction f;
f = new myFunction(MyDelegates.MyFunctions.functionInstance.Get("Test2"));
The same applies to using it in the MyState-call later.
Another way to work around this is to just use Func<object, int> everywhere instead of the myFunction delegate.
I've got a function,
public SharpQuery Each(Action<int, HtmlNode> function)
{
for (int i = 0; i < _context.Count; ++i)
function(i, _context[i]);
return this;
}
Which calls the passed in function for each element of the context. Is it possible to set what "this" refers to inside Action<int, HtmlNode> function?
For example,
sharpQuery.Each((i, node) => /* `this` refers to an HtmlNode here */);
With a slight change in the function, you can achieve the desired effect.
public SharpQuery Each(Action<MyObject, int, HtmlNode> function)
{
for (int i = 0; i < _context.Count; ++i)
function(this, i, _context[i]);
return this;
}
Then you could write your function call like so:
sharpQuery.Each((self, i, node) => /* do something with `self` which is "this" */);
Note: The anonymous function will only have access to public members however. If the anonymous function was defined within the class, it will have access to protected and private members as usual.
e.g.,
class MyObject
{
public MyObject(int i)
{
this.Number = i;
}
public int Number { get; private set; }
private int NumberPlus { get { return Number + 1; } }
public void DoAction(Action<MyObject> action)
{
action(this);
}
public void PrintNumberPlus()
{
DoAction(self => Console.WriteLine(self.NumberPlus)); // has access to private `NumberPlus`
}
}
MyObject obj = new MyObject(20);
obj.DoAction(self => Console.WriteLine(self.Number)); // ok
obj.PrintNumberPlus(); // ok
obj.DoAction(self => Console.WriteLine(self.NumberPlus)); // error
No.
Well, yes, if the Action was created in such a scope where 'this' was available and bound in a closure -- but transparently: no.
Pass in all needed information or make sure it's captured/available in the Action itself. There are other hacks like thread-locals, etc. Best avoided.
Long switch statments are often frowned upon. The solution is to use polymorphism. However what if the thing I'm switching on is not a type code? What I would like to do is replace the switch statement with something like this...
public void HandleString(string s = "Hello")
{
...
}
public void HandleString(string s = "Goodbye")
{
...
}
...
HandleString("Hello"); // results in the first method being called.
This would replace the following...
string s = "Hello";
switch(s)
{
case "Hello":
...
break;
case "Goodbye":
...
break;
default;
break;
}
Any ideas? In theory I think you could do away with 'if/switch' statements altogether and just call methods that are automatically bound based on the value of an expression.
If you have a large number of options, and high possibility that there will be more in the future - or you just need to system to be easily extensible - then you can always use an explicit dispatch table:
Dictionary<string, Action<string>> actions =
new Dictionary<string, Action<string>>()
{
{ "Hello", HandleHello },
{ "Goodbye", HandleGoodbye }
};
private static void HandleHello(string s) { ... }
private static void HandleGoodbye(string s) { ... }
...
actions[s](s);
You can also provide a way to extend the table by allowing external clients of your API to register their own handler for a given string.
There are languages that implement that sort of semantics. One that I'm familiar with is the compiler generator tool called Elegant from Phillips.
In a language like this, a simple factorial algorithm might look like:
fact (value : Int) : Int
conditions value < 0
{
{ "Illegal input value\n" } astype Message
return 0
}
fact (value = 0) : Int
{
return 0
}
fact (value = 1) : Int
{
return 1
}
fact (value : Int) : Int
{
return value * fact(value - 1);
}