Get all concrete implementations of a delegate collection in C# via reflection - c#

Yeah, I tried to make the title smaller, but I couldn't.
I'm very new to reflection, so I'm struggling with a problem that I don't know if it's even possible to solve.
I'll use some simple delegate example to describe it.
public void Main() {
var manager = new EvManager();
var class1 = new Class1(manager);
var class2 = new Class2(manager);
manager.ExecuteIt(5, 12);
/*
This outputs:
In Class1 -> 17
In Class2 -> 18
*/
}
public class EvManager {
public delegate void SumDelegate(int a, int b);
private SumDelegate sum;
public void AddDelegate(SumDelegate s) {
sum += s;
}
public void ExecuteIt(int a, int b) {
sum.Invoke(a, b);
}
}
public class Class1 {
public Class1(EvManager m) {
m.AddDelegate(MySum);
}
private void MySum(int a, int b) {
Console.Write("In Class1 -> " + (a + b));
}
}
public class Class2 {
public Class2(EvManager m) {
m.AddDelegate(MyOtherSum);
}
private void MyOtherSum(int a, int b){
Console.Write("In Classe2 -> " + (a + b));
}
}
Okay, that's the example. What do I want from it? I want, through the EvManager "sum" delegate property be able to access the concrete implementations of all the methods that it invokes.
This is basically what I want:
class EvManager {
private SumDelegate sum;
public void ExecuteIt(int a, int b) {
var invocationList = sum.GetInvocationList();
foreach (var m in invocationList) {
// m is a reference to the annonymous call.
// Through reflection, I want to access the concrete method name.
// In this case, the first iteration "MySum", and the second "MyOtherSum"
// Is this possible?
// Like...
// var concreteMethodName = m.GetMethod().ConcreteCallerType.GetMethod(m.GetConreteMethodName());
// Or something like that?
}
}
}
Hope I made my problem clear, this is killing me.

The Method property holds the information about the real method:
var mName = m.Method.Name;

You can add the following method to EvManager:
public void ListDelegates()
{
foreach (var m in sum.GetInvocationList())
{
Console.WriteLine(m.Method.Name);
}
}
Calling it will give you what you want:
MySum
MyOtherSum
Take a look here on a Delegate class reference.

Actually, it is very simple. Use the Method property.
Check this code:
using System;
namespace ConsoleApplication2
{
public class EvManager
{
public delegate int SumDelegate(int a, int b);
private SumDelegate sum;
public void AddDelegate(SumDelegate s)
{
sum += s;
}
public void ExecuteIt(int a, int b)
{
foreach (var m in sum.GetInvocationList())
{
Console.WriteLine("{0}({1}, {2}) = {3}", m.Method.Name, a, b, m.DynamicInvoke(a, b));
}
}
}
public class Class1
{
public Class1(EvManager m)
{
m.AddDelegate(FakeSum);
}
public int FakeSum(int a, int b)
{
return a - b;
}
}
public class Class2
{
public Class2(EvManager m)
{
m.AddDelegate(RealSum);
}
public int RealSum(int a, int b)
{
return a + b;
}
}
class Program
{
static void Main(string[] args)
{
var manager = new EvManager();
var class1 = new Class1(manager);
var class2 = new Class2(manager);
manager.ExecuteIt(5, 12);
}
}
}
Output:
FakeSum(5, 12) = -7
RealSum(5, 12) = 17

You can get the MethodInfoof each one of your split up delegates through the Method Property of the Delegate which has Name property.
class EvManager {
private SumDelegate sum;
public void ExecuteIt(int a, int b) {
var invocationList = sum.GetInvocationList();
foreach (var m in invocationList) {
var concreteMethodName = m.Method.Name;
}
}
}

Related

C# There is no argument given that corresponds to the required

I am receiving an error: There is no argument given that corresponds to the required formal parameter 'x' of ReadingMaterial.By(string). I'm looking for a little guidance as to why there is an error. Is my syntax wrong, or is there something else I'm missing? I have been trying to learn C# by using some online tutorials and trying to change them up a bit.
namespace ReadingMaterials
{
class Presentation
{
static void Main(string[] args)
{
aForm Form = new aForm(); // available in hardcopy form aForm.availForm
Online O = new Online(); // amtBlogs, amtBooks
Book B = new Book(); // hardCover, softCover
Magazine M = new Magazine(); // numArticles
O.blog(5); //contains 5 blogs
O.oBook(3); //contains 3 online books
O.By("Beck"); //Written by Beck
O.words(678); //with 678 combined words
O.pics(1); // with one pic
Console.WriteLine("The auther {0} ", O.By());
Form.availForm();
B.hardCover(10); //10 hardcover books
B.softCover(2); //2 softcover books
B.By("Bruce"); //Writen by Bruce
B.words(188264); //words combined
B.pics(15); //15 pictures
Form.availForm();
M.articles(5); //5 articles
M.By("Manddi"); //Writen by Manddi
M.words(18064);//combined words
M.pics(81); //81 pictures
Form.availForm();
}
}
class ReadingMaterial
{
protected int amtWords;
string author;
protected int pic;
public void words(int w)
{
amtWords = w;
}
public void By(string x)
{
author = x;
}
public void pics(int pi)
{
pic = pi;
}
}
class Online : ReadingMaterial
{
int amtBlogs;
int amtBooks;
public void blog(int s)
{
amtBlogs = s;
}
public void oBook(int b)
{
amtBooks = b;
}
}
class Book : ReadingMaterial
{
int hard;
int soft;
public void hardCover(int h)
{
hard = h;
}
public void softCover(int s)
{
soft = s;
}
}
class Magazine:ReadingMaterial
{
int numArticles;
public void articles(int a)
{
numArticles = a;
}
}
interface IPrintable
{
void availForm();
}
class aForm : IPrintable
{
public void availForm ()
{
Console.WriteLine("Available in hard copy form!");
}
}
}
Console.WriteLine("The auther {0} ", O.By()); is the culprit. O.By() expects a string, and the By() function sets the author, but doesn't return any string. Since you've set the author using the By() function, you can make the author a public field, and do Console.WriteLine("The auther {0} ", O.author);
The problem is that you are calling By without any parameters in this line:
Console.WriteLine("The auther {0} ", O.By());
You can add a method to get the value instead:
class ReadingMaterial
{
...
public string GetBy()
{
return author;
}
....
}
Anyways, you might want to use properties instead of functions. You can look at the code working in here
class ReadingMaterial
{
public string Author {get;set;}
...
}
static void Main(string[] args)
{
...
O.Author = "Beck"; //Written by Beck
...
Console.WriteLine("The auther {0} ", O.Author);
}
You have defined the By method like this, with a parameter:
public void By(string x)
{
author = x;
}
But you are trying to call it without a parameter:
Console.WriteLine("The auther {0} ", O.By()); // not passing a parameter to 'By()'
If you want to access the author value of ReadingMaterial here then I would suggest making it a public property rather than a private field:
class ReadingMaterial
{
protected int amtWords;
public string Author { get; private set;}
// skipped
public void By(string x)
{
Author = x;
}
All of which kinds of begs the question - why use methods to set the values at all? Why not just use properties, as suggested below by #CarlosGarcia?

How to fix this ISeries interface implementation in Class1?

I am developing a series of numbers starting from Setstart(2) function from ISeries interface. I tried to implement this interface in Class1 but it threw an error to me. And I am getting stuck at this error and not been able to figure out to fix this. What am I missing? Please help
I tried to make all functions in the interface public
I tried to remove public access specifier from interface
public interface ISeries {
void Setstart (int a);
int GetNext ();
void Reset ();
}
class Class1 : ISeries {
int val;
void Setstart (int a) {
val = a;
}
int GetNext () {
return val++;
}
void Reset () {
val = 0;
}
static void Main () {
Class1 c = new Class1 ();
c.Setstart (2);
Console.WriteLine (c.GetNext ());
c.Reset ();
Console.WriteLine ();
}
}
I expect the output to be 3 and 0 error is being generated
Your should try something like this.
Because you have to play with one variable so you have to make use of ref `keyword in this case.
and also you have to mark all the method inside a class as a public otherwise you were not be able to access those method inside main
Code:
using System;
namespace StackoverflowProblem
{
public interface ISeries
{
void Setstart(ref int value);
int GetNext(ref int value);
void Reset(ref int value);
}
public class Class1 : ISeries
{
public int val { get; set; }
public void Setstart(ref int value)
{
this.val = value;
}
public int GetNext(ref int value)
{
value = value + 1;
this.val = value;
return this.val;
}
public void Reset(ref int value)
{
// Resetting val.
value = 0;
this.val = value;
}
}
class Program
{
static void Main(string[] args)
{
Class1 c = new Class1();
int value = 2;
c.Setstart(ref value);
Console.WriteLine(" " + c.GetNext(ref value));
c.Reset(ref value);
Console.WriteLine();
}
}
}
Output:
val++ will incriment after returning the current value, ++val will increment first then return the value, you should now get 3, also make it proper scoped to access the methods from outside
class Class1 : ISeries {
int val;
public void Setstart (int a) {
val = a;
}
public int GetNext () {
return ++val;
}
public void Reset () {
val = 0;
}
static void Main () {
Class1 c = new Class1();
c.Setstart(2);
Console.WriteLine (c.GetNext());
c.Reset();
Console.WriteLine ("");
}
}
You need to make your methods public to be accessible outside from class which is missing other than that your code looks fine.
You need to make all the 3 methods public as per your scenario like :
public void Setstart (int a) {
and you will need to first add 1 and then return to get 3 as output as val++ will return the current value and then increment it by 1:
public int GetNext () {
// return val++; // Post increment will not work according to question.
val = val + 1;
return val;
}
Your class with complete implementation of Interface would be like following:
public class Class1 : ISeries {
int val;
public void Setstart (int a) {
val = a;
}
public int GetNext () {
val = val + 1;
return val;
}
public void Reset () {
val = 0;
}
}

How to Count the object instace using Static property in C#.(Not using Costrutor0)

I want to count the number of instance and I want to call The set accessor or Modifiers of property in c3 at the time of object creation can I?
call set at object
class a {
private static int x;
public static int X {
get {
return x;
}
set { //Call This area while oblect Creation }
}
}
class Program {
static void Main(string[] args) {
a o = new a();
a ob = new a();
Console.WriteLine("Count is: " + a.X);
}
}
To my mind, the only reasonably approach here is:
class a {
private static int x;
public static int X { get { return x; } }
public a()
{
Interlocked.Increment(ref x);
}
...
}
Now yes, the question title says "not using constructor", but: if you want to count how many instances of a type have been created - the appropriate place to put that code is in the constructor.
The Interlocked.Increment(ref x); could be replaced with x++; if you don't care about the answer being right when using multiple threads.
You could also satisfy the "not using constructor" by using a factory method:
private a() {}
public static a Create()
{
Interlocked.Increment(ref x);
return new a();
}
but if you do that, the new a() in the Main() method no longer works, and needs to be changed to a.Create().
If you don't want to use a constructor to increment your x variable you can call a static method which increments the value of x and creates a new instance of your a class:
static void Main(string[] args)
{
a o = a.incrementX();
a ob = a.incrementX();
Console.WriteLine("Count is: " + a.X);
}
The static method incrementX is defined in your class:
class a
{
private static int x;
public static int X
{
get { return x; }
set { x = value;}
}
public static a incrementX()
{
X++;
return new a();
}
}
use this:
class a
{
private static int x;
public static int X
{
get { return x; }
set { //Call This area while oblect Creation }
}
}
class Program
{
static void Main(string[] args)
{
a o = new a();
a.X += 1;
Console.WriteLine("Count is: " + a.X);
}
}
You access static field without initializing the object and so you set it's value.

c# Why delegate\event doesn't get updated after passing it to another class

I'm having trouble invoking delegates that were added after I pass the event to a specific class, I thought that the delegate get updates as objects..
For example this the class that I'm passing the delegate to:
Updated code (due to some question in the comments)
This is actually +- how I need to run it, Where "ExecutorOnCalculationCompleted" is never invoking (please ignore sleep, and synchronization, I shrink my code to the needed parts)
class Executor
{
public delegate void CalculationCompletEventHandler(int score);
public event CalculationCompletEventHandler CalculationCompleted;
public void Start()
{
CalculationCompleted += OnCalculationCompleted;
Plus plus = new Plus(1, 2, CalculationCompleted);
Minus minus = new Minus(5, 2, CalculationCompleted);
Multi multi = new Multi(5, 2, CalculationCompleted);
...
... They will work async...
}
private void OnCalculationCompleted(int score)
{
Console.WriteLine("OnCalculationCompleted , score=" + score);
}
}
class Plus
{
private Executor.CalculationCompletEventHandler _calculationCompletEventHandler;
private int a;
private int b;
public Plus(int a, int b,Executor.CalculationCompletEventHandler calculationCompletEventHandler)
{
this.a = a;
this.b = b;
_calculationCompletEventHandler = calculationCompletEventHandler;
}
public void Calculate()
{
_calculationCompletEventHandler?.Invoke(a+b);
}
}
class Program
{
static void Main(string[] args)
{
Executor executor = new Executor();
executor.Start(); // async action
executor.CalculationCompleted += ExecutorOnCalculationCompleted;
...
}
// This method doesn't get invoked when the class inside Executor fire the event.
private static void ExecutorOnCalculationCompleted(int score)
{
Console.WriteLine("ExecutorOnCalculationCompleted , score=" + score);
}
}
You are passing the delegate directly in the constructor. I think you want to put the event into the class. Example:
class Plus
{
public delegate void CalculationCompletEventHandler(int score);
public event CalculationCompletEventHandler CalculationCompleted;
private int a;
private int b;
public Plus(int a, int b)
{
this.a = a;
this.b = b;
}
public void Calculate()
{
if (CalculationCompleted != null)
{
CalculationCompleted(a + b);
}
}
}
you can now use it like that:
void Main()
{
Plus plus = new Plus(1, 2);
plus.CalculationCompleted += OnCalculationCompleted;
plus.Calculate();
plus.CalculationCompleted += OnCalculationCompleted2;
plus.Calculate();
}
private void OnCalculationCompleted(int score)
{
Console.WriteLine("OnCalculationCompleted , score=" + score);
}
private void OnCalculationCompleted2(int score)
{
Console.WriteLine("OnCalculationCompleted2 , score=" + score);
}
As mentioned in the comment, you maybe only need the event itself if the delegate type is used in different parts of your program.
After Update in Question
If you want the event in the executor, I would simply pass an action to each of your classes like Plus, Multiply, ... and invoke the event from the executor:
class Executor
{
public delegate void CalculationCompletEventHandler(int score);
public event CalculationCompletEventHandler CalculationCompleted;
public void Start()
{
CalculationCompleted += OnCalculationCompleted;
Plus plus = new Plus(1, 2, FireEvent);
}
private void FireEvent(int score)
{
if (CalculationCompleted != null)
{
CalculationCompleted(score);
}
}
private void OnCalculationCompleted(int score)
{
Console.WriteLine("OnCalculationCompleted , score=" + score);
}
}
class Plus
{
private int a;
private int b;
private Action<int> completionAction
public Plus(int a, int b, Action<int> completionAction)
{
this.a = a;
this.b = b;
this.completionAction = completionAction;
}
public void Calculate()
{
this.completionAction(a + b);
}
}

How to handle base class constructors in C#?

I have a class that extends a base class. The base class is more generic, and thus needs more parameters. The derived class is a specific type of base class, and thus only needs one of the two parameters the base class needs in its constructor (the derived class can provide the base class with the second parameter, but needs to do some processing first).
Is it possible to have a constructor in the derived class that then invokes the base classes constructor?
I'm aware I could just use : base(int a, int b) if the parameters were passed in directly, but I don't think I can do this since I need to process the second variable before calling the base class constructor.
class Foo {
private int c;
public Foo(int a, int b) {
c = a + b;
}
}
class Bar : Foo {
public Bar(int a, bool plusOrMinus) {
if (plusOrMinus) {
Foo(a, 5); // calling base class constructor- AFTER processing
} else {
Foo(a, -5); // calling base class constructor- AFTER processing
}
}
}
One way to do this is to use the ternary operator
public Bar(int a, bool plusOrMinos) : base(a, plusOrMinus ? 5 : -5) {
...
}
For more complex conditionals though you should switch to a static factory method
private Bar(int a, int b) : base(a, b) {
...
}
public static Bar Create(int a, bool plusOrMinus) {
if (plusOrMinus) {
return new Bar(a, 5);
} else {
return new Bar(a, -5);
}
}
You can just do it inline, no?
public Bar(int a, bool plusOrMinus) : base(a, plusOrMinus ? 5 : -5) {
}
If you need to do something more sophisticated, you can extract the logic out into a static method:
public Bar(int a, bool plusOrMinus) : base(a, GetValueFromPlusOrMinus(plusOrMinus)) {
}
public static int GetValueFromPlusOrMinus(bool plusOrMinus)
{
if (plusOrMinus)
return 5;
else
return -5;
}
You can more or less do this if you can write a static function to process the data:
class Bar : Foo
{
public Bar(int a, bool plusOrMinus) : base(a, calc(plusOrMinus))
{
}
private static calc(bool pom) : ...; return -5; }
}
My suggestion is to use composition instead of inheritence.
Instead of having a bunch of subclasses (A, B, C) derive from your base class (X), instead have A, B, C contain a private instance of X that they can call.
This way you only have the shared logic in one place (X) and all your classes are able to use it.
class Foo {
private int c;
public Foo(int a, int b) {
c = a + b;
}
}
class Bar {
private Foo _base;
public Bar(int a, bool plusOrMinus) {
if (plusOrMinus) {
_base = new Foo(a, 5);
} else {
_base = new Foo(a, -5);
}
}
}
How about this approach?
class Foo
{
private int c;
public Foo(Builder builder)
{
c = builder.A ?? 0 + builder.B ?? 0;
}
}
class Bar : Foo
{
public Bar()
: base(new Builder().WithA(2).WithB(3).WithPlusOrMinus(false))
{
}
}
public class Builder
{
public int? A { get; private set; }
public int? B { get; private set; }
public bool? PlusOrMinus { get; private set; }
public Builder WithA(int a)
{
A = a;
return this;
}
public Builder WithB(int b)
{
B = b;
return this;
}
public Builder WithPlusOrMinus(bool plusOrMinus)
{
if(!plusOrMinus)
{
B *= -1;
}
return this;
}
}
I would prefer making a protected Initialize(...) on the base class and call this at the end of the ctr in the inherited class.

Categories

Resources