C# - Passing Delegate as a parameter to a method - c#

I am trying to get familiar with the concept of delegates in C#. I have created this console application so far:
Program.cs
using System;
namespace DelegatesTest
{
class Program
{
static void Main(string[] args)
{
ArithmeticOperation.ArOpDel additionDelegate = new ArithmeticOperation.ArOpDel(ArithmeticOperation.Addition);
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate(10, 5)));
Console.ReadKey();
}
}
}
ArithmeticOperation.cs
using System;
namespace DelegatesTest
{
public static class ArithmeticOperation
{
public delegate int ArOpDel(int x, int y);
public static string ConvertResultToString(ArOpDel del)
{
string result = String.Format("The result of the {0} operation is {1}", del.Method.Name, del.ToString());
return result;
}
public static int Addition(int x, int y)
{
return x + y;
}
public static int Subtraction(int x, int y)
{
return x - y;
}
public static int Multiplication(int x, int y)
{
return x * y;
}
public static int Division(int x, int y)
{
return x / y;
}
}
}
As you can see from the code, I am using a static class called ArithmeticOperation.cs to perform some arithmetic operations. The ConvertResultToString method takes one of the arithmetic operations methods as a parameter in order to display the result elegantly as a string.
Unfortunately, my code does not compile. It is giving me the following error:
Argument '1': cannot convert from 'int' to 'DelegatesTest.ArithmeticOperation.ArOpDel'
The error is being given on this line:
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate(10, 5)));
Can you please help me solve this problem as I am not very experienced with delegates? In fact, I have created this application to learn about delegates.

The additionDelegate(10, 5) will return int by doing arithmetic operation, it will not return deleagate that's the reason of compilation error.

Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate(10, 5)));
You are not passing the delegate here. You are calling it, which results in an int.
This would pass the delegate:
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate));
You would need to actually call the delegate somewhere though.

when you do this
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate(10, 5)));
you are forcing the compiler to execute the method and return the result to pass it as an argument which in this case it's an int while the ConvertResultTostring expect a delegate
here how you can get it work without using generic
class Program
{
static void Main(string[] args)
{
ArithmeticOperation.ArOpDel additionDelegate = ArithmeticOperation.Addition;
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate,5,6));
Console.ReadKey();
}
}
public static class ArithmeticOperation
{
public delegate int ArOpDel(int x, int y);
public static string ConvertResultToString(ArOpDel del,int x, int y )
{
string result = String.Format("The result of the {0} operation is {1}", del.Method.Name, del(x,y).ToString());
return result;
}
public static int Addition(int x, int y)
{
return x + y;
}
public static int Subtraction(int x, int y)
{
return x - y;
}
public static int Multiplication(int x, int y)
{
return x * y;
}
public static int Division(int x, int y)
{
return x / y;
}
}

additionDelegate(10, 5) is an invocation of additionDelegate which actually is an Addition function. So, the result is an integer.
In order to pass a delegate you should pass additionDelegate itself instead of additionDelegate(10, 5). But, in this case, the result of the operation will not be available in ConvertResultToString unless you invoke it there.
public static string ConvertResultToString(ArOpDel del)
{
string result = String.Format("The result of the {0} operation is {1}", del.Method.Name, del(10, 5).ToString());
return result;
}
...
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate));

additionDelegate(10, 5) means invoke the delegate,the result is an int type which does not match the ConvertResultToString method stub.
you need change
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate(10, 5)))
to
Console.WriteLine(ArithmeticOperation.ConvertResultToString(additionDelegate))
and change
string result = String.Format("The result of the {0} operation is {1}", del.Method.Name, del.ToString());
to
string result = String.Format("The result of the {0} operation is {1}", del.Method.Name, del(10,5).ToString());

Related

Printing Calculation result

I'm trying to write a print function that would help me with printing the results of the addition, subtraction, etc.
I've tried to do this in a switch - case statement, but it doesn't seems to be working.
Is there any easier ways to implement this print() function?
Secondly, in case of exception, how can I manage exceptions if for instance one of the operations throw an exception. such as 3/0!
for this program I have a Calculator class and a Program, where all this will be tested.
public class Calculator
{
public double Add(double x, double y)
{
return x + y;
}
public double Subtract(double x, double y)
{
return x - y;
}
public double Multiply(double x, double y)
{
return x * y;
}
public double Power(double x, double y)
{
return Math.Pow(x, y);
}
public void PrintCalculation(string action)
{
switch (action)
{
case "Add":
Console.WriteLine("Sum is: {0}", Add(x, y));
break;
case "Subtract":
Console.WriteLine("Division is: {0}", Subtract(x, y));
break;
case "Multiply":
Console.WriteLine("Multiply is: {0}", Multiply(x, y);
break;
case "Power":
Console.WriteLine("Power is: {0}", Power(x, y);
break;
}
}
}
This is the Main function
namespace MyCalculator
{
public class Program : Calculator
{
static void Main()
{
Calculator myCal = new Calculator();
myCal.Add(2, 3);
myCal.Subtract(3, 3);
myCal.Multiply(5, 5);
myCal.Power(2, 3);
myCal.PrintCalculation("Add");
myCal.PrintCalculation("Subtract");
myCal.PrintCalculation("Multiply");
}
}
}
A few issues, first of all you are not passing strings into PrintCalculation(string s). The format should be something like:
PrintCalculation("Add");
As the function is currently defined. Also in PrintCalculation() you call your calculation functions which are then passed undefined values of x and y. They are not members of the class or the class method itself.
For example you are trying to call Add(x,y) inside of PrintCalculation("Add"), but you never give it an x or y in that function. Instead the function should be defined
public void PrintCalculation(string action, double x, double y){
// code here
}
And it should be called with
PrintCalculation("Add", 2, 3);
There are a few problems with the code that are causing compiler errors, such as missing parenthesis, quotes, and break statements. But I think the main issue is that you're not taking in the values of x and y to your PrintCalculation method, so they are undefined in the body of that method.
To fix this, you can just add them to the argument list as you have with the other methods:
public static void PrintCalculation(string action, double x , double y)
But notice that you're doing a string comparison here, which can be prone to errors due to case sensitivity (what happens if they write "add" instead of "Add"?). A different option might be to create an enum to represent valid actions. This also serves to restrict the input allowed to only values we can do something with (previously the user may have tried to enter "Divide", and been confused when nothing happened):
public enum Action { Add, Subtract, Multiply, Power }
Then your method could be changed to accommodate the enum instead of a string. We can also make the class and methods static, since there is no state required:
public static class Calculator
{
public enum Action { Add, Subtract, Multiply, Power }
public static double Add(double x, double y)
{
return x + y;
}
public static double Subtract(double x, double y)
{
return x - y;
}
public static double Multiply(double x, double y)
{
return x * y;
}
public static double Power(double x, double y)
{
return Math.Pow(x, y);
}
public static void PrintCalculation(Action action, double x , double y)
{
switch (action)
{
case Action.Add:
Console.WriteLine("The sum of {0} and {1} is: {2}",
x, y, Add(x, y));
break;
case Action.Subtract:
Console.WriteLine("The difference between {0} and {1} is: {2}",
x, y, Subtract(x, y));
break;
case Action.Multiply:
Console.WriteLine("The product of {0} and {1} is: {2}",
x, y, Multiply(x, y));
break;
case Action.Power:
Console.WriteLine("{0} raised to the power of {1} is: {2}",
x, y, Power(x, y));
break;
}
}
}
With these changes, we can now use the class like:
private static void Main(string[] cmdArgs)
{
var first = 7;
var second = 3;
Calculator.PrintCalculation(Calculator.Action.Add, first, second);
Calculator.PrintCalculation(Calculator.Action.Subtract, first, second);
Calculator.PrintCalculation(Calculator.Action.Multiply, first, second);
Calculator.PrintCalculation(Calculator.Action.Power, first, second);
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
I think you can take advantage of logging the actions without requiring a switch case at all. The example below allows you to set an Action<string> for logging the results dynamically.
public class Calculator
{
public Action<string> LogAction { get; set;}
private double PerformCalculation(string calculationName, string format, double x, double y, Func<double, double, double> calcFunction)
{
double value = calcFunction(x, y);
LogAction?.Invoke(string.Format(format, x, y, value));
return calcFunction(x, y);
}
public double Add(double x, double y)
{
string format = "The sum of {0} and {1} is: {2}";
return PerformCalculation("Add", format, x, y, (a, b) => a + b);
}
public double Subtract(double x, double y)
{
string format = "The difference between {0} and {1} is: {2}";
return PerformCalculation("Subtract", format, x, y, (a, b) => a - b);
}
public double Multiply(double x, double y)
{
string format = "The product of {0} and {1} is: {2}";
return PerformCalculation("Multiply", format, x, y, (a, b) => a * b);
}
public double Power(double x, double y)
{
string format = "{0} raised to the power of {1} is: {2}";
return PerformCalculation("Power", format, x, y, (a, b) => Math.Pow(a, b));
}
}
static void Main(string[] args)
{
Calculator myCal = new Calculator();
myCal.LogAction = Console.WriteLine; // Sets all calculation output to the console.
myCal.Add(2, 3);
myCal.Subtract(3, 3);
myCal.Multiply(5, 5);
myCal.Power(2, 3);
Console.ReadLine();
}
Your problemn is: you start the method to do something
Main:
myCal.Add(2, 3);
Class:
public double Add(double x, double y)
{
return x + y;
}
but you don't store the outcome anywhere. You see, the method knows to return something, but on the other end is nothing to receive it like
double i = myCal.Add(2, 3);
or, as an alternative you can store your numbers in the class
public double _outcome;
public void Add(double x, double y)
{
_outcome = x + y;
}
and in main
myCal.PrintCalculation(myCal._outcome.ToString());
As an alternative (to do it the way you actually want it to)
Main:
myCal.TmpNumberOne = 1;
myCal.TmpNumberTwo = 2;
myCal.PrintCalculation("Add");
Class:
public double TmpNumberOne;
public double TmpNumberTwo;
public double Add(double x, double y)
{
return x + y;
}
public void PrintCalculation(string action)
{
switch (action)
{
case "Add":
Console.WriteLine("Sum is: {0}", Add(TmpNumberOne, TmpNumberTwo).ToString());
break;
}
}
To your final question: you want exceptionhandling, first you coudl achieve this by adding an if-statement to your method to check for invalid inputs, or you take the holy
try
{
}
catch(Exception ex)
{
}
you can paste your code inside try, when an error would occur that stops the program entirely, the code in catch code is executed instead. If you are fancy you can print out the exception with
ex.ToString();
don't forget to convert your double values to string, otherwise this will throw an error

Compile error: Using the generic type requires N type arguments

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?

My delegate type isn't working "Method name expected"

I tried this:
class Program
{
public delegate int add(int x, int y);
public class ff
{
public static int addNumbers(int x, int y)
{
return x + y;
}
public static int substractNumbers(int x, int y)
{
return x - y;
}
static void Main(string[] args)
{
Delegate delegare = new add(ff.addNumbers);
Console.WriteLine(delegare(3,4));
}
}
I don't see why I'm getting this error"Method name expected".
When I use a delegate with a void function it works.
Can someone help me?
The type of your delegare variable is just Delegate. That could refer to any delegate. In order to invoke a delegate (in the normal way), you should have an expression of the appropriate type.
After fixing the naming conventions and removing the unnecessary nested class - and demonstrating a method group conversion - your code looks like this:
using System;
public delegate int Int32Operation(int x, int y);
class Program
{
public static int AddNumbers(int x, int y)
{
return x + y;
}
public static int SubtractNumbers(int x, int y)
{
return x - y;
}
static void Main(string[] args)
{
Int32Operation op = new Int32Operation(AddNumbers);
Console.WriteLine(op(3, 4)); // Prints 7
op = SubtractNumbers; // Method group conversion
Console.WriteLine(op(3, 4)); // Prints -1
}
}
You should try this out:
add delegare = new add(ff.addNumbers);
The type of your delegate should be add since you defined so.

C# extension using function Func as parameter

Please don't be confuse with the code, the code is wrong. Focused on the bold question below.
I've been preparing to study functional programming and just so at least be ready for its prerequisites, I've been studying extensions, functions and lambda expressions.
This code below is NOT working I just thought this is how it should be coded:
Program:
class Program
{
static void Main(string[] args)
{
int s = 10;
int t = s.CreatedMethod(2, 3); // <-- the one that calls the extension
Console.WriteLine(t.ToString());
Console.ReadLine();
}
static int RegularMethod(int v1, int v2)
{
return v1 * v2; // <-- I also wanted to multiply int 's' like this s*v1*v2
}
}
Extension:
public static class Extension
{
public static int CreatedMethod(this int number, Func<int, int, int> fn)
{
// I'm expecting that the code here will read the
// RegularMethod() above
// But I don't know how to pass the parameter of the function being passed
return #fn(param1, param2)// <-- don't know how to code here ??
}
}
As you can see, the CreateMethod extended my integer 's'. My plan is to pass the two parameters in CreateMethod() above and multiply those two parameters into 's'
In the example above, the answer should be 60.
Can you help me do it using extension?
This might be what you're looking for but it doesn't make sense to pass a function as a parameter or maybe I'm just missing something. Anyway, it works:
class Program
{
static void Main(string[] args)
{
int s = 10;
// the function we're passing as a parameter will multiply them
// then return the result
int t = s.CreatedMethod((param1, param2) => param1 * param2);
// or you can use this since the method signature matches:
// int t = s.CreatedMethod(RegularMethod);
Console.WriteLine(t.ToString()); // outputs "60"
Console.ReadLine();
}
static int RegularMethod(int v1, int v2)
{
return v1 * v2; // <-- I also wanted to multiply int 's' like this s*v1*v2
}
}
public static class Extension
{
public static int CreatedMethod(this int number, Func<int, int, int> fn)
{
return number * fn.Invoke(2, 3);
}
}
Following up on OP's comment: If you don't want to hardcode the values then you'll need to change the CreateMethod's signature to this:
public static int CreatedMethod(this int number, int val1, int val2, Func<int, int, int> fn)
then call Invoke like this:
fn.invoke(val1, val2)
Extension could look like this:
public static int CreatedMethod(this int number1, int number2, Func<int, int, int> fn) {
fn(number1, number2);
}
And then call would be:
var s = 10;
var t = s.CreatedMethod(2, RegularMethod).
CreatedMethod(3, RegularMethod);
This will first call RegularMethod with 10 and 2 and second time with 20 and 3.
Additional way would be to use extension like
public static int CreatedMethod(this int number1, int number2, int number3, Func<int, int, int> fn) {
fn(fn(number1, number2), number3);
}
And call like
var s = 10;
var t = s.CreatedMethod(2, 3, RegularMethod);

How to access Interface method implemented in the derived class from child class?

I have two interfaces A,B both has same method declarations. I have a class C inheriting from interfaces A,B. I have another class D inheriting from C. Now i want to access the implemented methods in C from D
interface A
{
int add(int x, int y);
int mul(int x, int y);
}
interface B
{
int add(int x, int y);
int mul(int x, int y);
}
public class C : A,B
{
int A.add(int x,int y)
{
return x + y;
}
int A.mul(int x,int y)
{
return 0;
}
int B.add(int x, int y)
{
return x;
}
int B.mul(int x, int y)
{
return y;
}
}
class D : C
{
}
How to access the methods in C from D?
How to access the methods in C from D?
You have to use a reference with a compile-time of the relevant interface. For example:
class D
{
public void FooA()
{
A a = this;
Console.WriteLine(a.mul(...));
}
public void FooB()
{
B b = this;
Console.WriteLine(b.mul(...));
}
}
Of course you don't need the local variable - you can cast:
Console.WriteLine(((A) this).mul(...));
... but it gets a bit ugly.
This is just because you're using explicit interface implementation. If you implemented one of the interfaces implicitly, you could just call the methods directly as normal... but explicit interface implementation only allows a member to be called via that interface.
An explicit interface method invocation should always work
((A)this).mul(1,1);
You can use this code because you have to specify the interface from which you want to use the method (A or B):
((A)this).add(1, 1);
As others already suggested casting is of course one way of doing this. It's quick and simple but if you're going to use it a lot it's annoying. The way out in this case are properties that give access to the members provided by the interface and that conveniently group them thus simplifying their usage:
Easy access without additional casting (you do it only once inside the property getters - see below the C-class):
class Program
{
static void Main(string[] args)
{
C c = new C();
c.As.add(1, 2);
}
}
Interfaces:
public interface A
{
int add(int x, int y);
int mul(int x, int y);
}
public interface B
{
int add(int x, int y);
int mul(int x, int y);
}
C-class:
public class C : A, B
{
// Methods from the A-interface.
public A As { get { return (A)this; } }
// Methods from the B-interface.
public B Bs { get { return (B)this; } }
int A.add(int x, int y)
{
return x + y;
}
int A.mul(int x, int y)
{
return 0;
}
int B.add(int x, int y)
{
return x;
}
int B.mul(int x, int y)
{
return y;
}
}
D-class:
public class D : C
{
public D()
{
base.As.add(1, 2);
base.Bs.add(3, 4);
}
}
Can you check this,
using System;
public class Program
{
public static void Main()
{
D ds=new D(10,12);
int valueAddtion=((A)ds).add(20,122);
int valueMultiplication=((B)ds).mul(20,11);
Console.WriteLine("Mainapplicatin Value of A= " +valueAddtion+" multiplication value= "+valueMultiplication);
}
}
// your code segment here
class D : C
{
public D()
{
int valueAdd=((A)this).add(10,11);
int valueMul=((B)this).mul(20,11);
Console.WriteLine("Addition Value of A= " +valueAdd+" multiplication value= "+valueMul);
}
public D(int x,int y):this()
{
int valueAdd=((A)this).add(x,y);
int valueMul=((B)this).mul(x,y);
Console.WriteLine("Paremeterized Value of A= " +valueAdd+" multiplication value= "+valueMul);
}
}
Output will be,
Addition Value of A= 21 multiplication value= 11
Paremeterized Value of A= 22 multiplication value= 12
Mainapplicatin Value of A= 142 multiplication value= 11

Categories