Passing delegate from class to class - c#

I have two classes, first:
public class A
{
public delegate void Function();
public string name;
public Function function;
public A(string name, Function function)
{
this.name = name;
this.function = function;
}
}
And in second:
public class B
{
public delegate void Function();
List<A> ListA;
// somewhere in function
void F()
{
ListA[i].function();
}
// ---
public void AddA(string name, Function function)
{
ListA.Add(new A(name, function)); // error here
}
}
It throws these errors:
Error 2 Argument 2: cannot convert from 'App.B.Function' to 'App.A.Function'
Error 1 The best overloaded method match for 'App.A.A(string, App.A.Function)' has some invalid arguments
How to solve this?

You have declared Function delegate twice, one inside class A and one inside B.
So they're two different types, one called App.B.Function and the other called App.A.Function.
If you want to share this delegate with both the classes, just declare it once and out of the scope of the classes (i.e. in the assembly scope) e.g.:
public delegate void Function();
public class A
{
public string name;
...
}
public class B
{
List<A> ListA;
...
}
However, in the System namespace exist a certain number of generic delegates that can be used to represent various functions. Have a look at System.Action<> and System.Func<> types.

The reason it happen is that Function is declared twice, once in each clases

Related

Passing child method to base constructor

I have a base class that implements some logic and eventually calls an Action which was passed to the contructor.
public class BaseClass
{
private Action action;
public BaseClass(Action someAction)
{
action += someAction;
}
private void doStuff()
{
action();
}
}
Now I want to derive some child classes that implement some specific logic. In these child classes I have a method for that logic and my attempt was to pass this method to the base constructor. But this result in a compiler error CS0120: An object reference is required for the nonstatic field, method, or property 'member'.
public class SpecificClass : BaseClass
{
private int b;
public SpecificClass(int i)
: base(doSpecificStuff) // <-- compiler error CS0120 here
{
b = i;
}
private void doSpecificStuff()
{
// do something depending on b
}
}
I don't quite get why it fails at that point. Is it because the base constructor gets called first which means when calling it I do not have an instance of the child class (including the child's method)?
But why does the compiler asks for a reference to a nonstatic field? Actually I don't see anything static here. Is there a way to get a reference to doSpecificStuff at that point? this.doSpecificStuff does not work, resulting in CS0027: Keyword 'this' is not available in the current context.
Any suggestions for a better design?
This is exactly where object-oriented-design (OOP) and one of its principles, Polymorphism, comes in place, and what it was designed for.
By making doStuff virtual in the base class, we can override the method in the specific class and customize its behavior.
public class BaseClass
{
private Action? action;
public BaseClass(Action someAction)
{
action += someAction;
}
protected BaseClass()
{
}
protected virtual void doStuff()
{
action?.Invoke();
}
}
public class SpecificClass : BaseClass
{
private int b;
public SpecificClass(int i)
{
b = i;
}
protected override void doStuff()
{
// do something depending on b
}
}
I don't quite get why it fails at that point. Is it because the base constructor gets called first which means when calling it I do not have an instance of the child class (including the child's method)?
Sort of. There is actually an instance of the child class (the object is created immediately of the "right" type) but you can't refer to anything specific to the instance in the constructor initializer.
From section 15.11.2 of the draft C# 6 spec:
An instance constructor initializer cannot access the instance being created.
The best way of handling this really depends on the broader context. For example, you could accept a Func<BaseClass, Action> instead and cast:
public class BaseClass
{
private Action action;
public BaseClass(Func<BaseClass, Action> actionProvider)
{
action += actionProvider(this);
}
private void doStuff()
{
action();
}
}
... then:
public class SpecificClass : BaseClass
{
private int b;
public SpecificClass(int i)
: base(x => ((SpecificClass) x).doSpecificStuff)
{
b = i;
}
private void doSpecificStuff()
{
// do something depending on b
}
}
That's a bit tortuous though. If the action is always expected to be a method in the derived class, an option would be to create an abstract method in the base class and just override it in the derived class instead.
The error message means that the compiler is expecting this:
private static void doSpecificStuff()
{
// do something depending on b
}
Why? because when you call your action in doStuff, C# has no way to now that doSpecificStuff has to be called on the current (this) instance.
To compile, you would have to do something like this :
public class BaseClass
{
private Action action;
public BaseClass(Action<BaseClass> someAction)
{
action += () => someAction(this);
}
private void doStuff()
{
action();
}
}
public class SpecificClass : BaseClass
{
private int b;
public SpecificClass(int i): base(x => ((SpecificClass)x).doSpecificStuff()) // <-- compiler error CS0210 here
{
b = i;
}
private void doSpecificStuff()
{
// do something depending on b
}
}
I do not know exactly why you came up with this approach but why not just us inheritance? (Again, there might be some specific need I'm not aware of here, I'm just mentioning this for the record to post an answer as complete as possible) For instance:
public class BaseClass
{
public BaseClass()
{
}
protected virtual void doStuff()
{
// Doing stuff...
}
}
public class SpecificClass : BaseClass
{
private int b;
public SpecificClass(int i): base()
{
b = i;
}
protected override void doStuff()
{
// do something depending on b
base.doStuff()// if needed...
}
}

C# - Is there a way to call a static method of a generic type in a class? [duplicate]

This question already has answers here:
Calling a static method on a generic type parameter
(9 answers)
Closed 3 years ago.
Example:
Public class a<T> where T: containsStatic
{
public void func()
{
T.StaticMethod();
}
}
Is it possible? And if not is there another way to do it?
EDIT:
it gives me the error: "'T' is a type parameter, which is not valid in the current context."
why is that? is there a way to fix this?
The problem I forsee with this is how do you guarantee that T supports StaticMethod?
However if you are sure that StaticMethod will always exist on T, you can use reflection to accomplish this fairly simply:
using System.Reflection;
public void func()
{
var staticMethod = typeof(T).GetMethod("StaticMethod", BindingFlags.Public | BindingFlags.Static);
staticMethod.Invoke(null, null);
}
Assume we wave a magic wand and you can do that now. Assume a type C:
public class C
{
public static void Foo()
{
}
}
How would this:
public class A<T> where T : C
{
public void Func()
{
T.Foo();
}
}
Be any different from:
public class A<T> where T : C
{
public void Func()
{
C.Foo();
}
}
It would not. It would have to be the same method being called. A static method call is generated statically (yeah, I know) when the method's code gets generated. The compiler seeing T.Foo() wouldn't possibly be able to insert any other call than C.Foo() there.
So you can't even express that in C#'s grammar, a type parameter is disallowed by the spec in such a context:
A type parameter cannot be used in a member access (Member access) or type name (Namespace and type names) to identify a static member or a nested type.
If you want to dynamically call a static method depending on T's value at runtime, refer to #Martin 's reflection solution.
You can call any static method, if it does not depend on the Generic Type.
If you have a class like
public class Test<T>
{
public static int Result => 5;
}
You can call
int n = Test<int>.Result;
at any place you want, and it is not important what type you actually insert, since any type will do the same
int n = Test<string[]>.Result;
will do the very same thing.
If your function depends on T like in
public class Test1<T>
{
public static void Action(T param)
{
}
}
You can use
Test1<int>.Action(8);
At any place you want.
Also inside other generic classes:
public class OtherClass<T>
{
public void Method(T param)
{
Test1<T>.Action(param);
}
}
But most often it is possible to write a generic function in a non-generic class like
public class Test2
{
public static void Action<T>(T param)
{
}
}
This works at any place in the Program
Test2.Action("string");
Test2.Action(9);
You can put this function in any class you want, since it's static. There is no need to put this function in a generic class.

C# Generics - Infer Type of static factory members

I would like to invoke static members of a class that uses generics without specifying the type and having the compiler infer them.
For example this is the generic class I want to use, with the Static Factory member:
public class GenericClass<T>
{
public T Member;
// Constructor
public GenericClass(T value)
{
Member = value;
}
// static factory method
public static GenericClass<T> StaticFactory(T resultData)
{
return new GenericClass<T>(resultData);
}
}
If I try the following does not compile:
public class Class1
{
public GenericClass<string> returnResult1()
{
return GenericClass.StaticFactory("Won't Compile, but it's clear that T is a string");
}
public GenericClass returnResult2()
{
return GenericClass.StaticFactory("Won't Compile, but it's clear that T is a string");
}
}
Error 1 Using the generic type 'SampleStatic.GenericClass' requires 1 type arguments
Why can't I do like the following with static members?
public void ICanInferTheType<T1>(T1 item);
public void returnResult4()
{
ICanInferTheType("Compiles, recognizes type string");
}
Thanks -
Generic inference only happens for method calls. In your case, you need it for referring to a class. Given class GenericClass<T> { ... }, any reference to GenericClass without a type parameter is a compilation error. The only time generic parameters can be inferred is for generic parameters declared on method signatures.
However, you can achieve your goal anyway. If you declare this additional class, you'll be able to invoke the method the way you want. That's because the generic parameters are moved to the method.
public static class GenericClass {
// static factory method
public static GenericClass<T> StaticFactory<T>(T resultData) {
return new GenericClass<T>(resultData);
}
}
Ok, thanks to #recursive! That answer is almost perfect, it requires one more in the name of the method, like this:
public static class GenericClass
{
// static factory method
public static GenericClass<T> StaticFactory<T>(T resultData)
{
return new GenericClass<T>(resultData);
}
}

How to make a derived method, which takes different arguments than overriden function in C#?

I have a class, something like this:
class BaseClass
{
protected int X;
virtual void ChangeParameters(int NewX)
{
this.X = newX;
}
}
class DerivedClass1 : BaseClass
{
private int a;
private int b;
}
class DerivedClass2 : BaseClass
{
private int a;
}
Problem comes when I want to override ChangeParameters() function in derived classes, because each of them can have different number of parameters.
So here comes the question - how can I create a virtual function, which can vary in arguments number in derived classes?
PS. I don't want to use the params keyword, because I'd much prefer the user of the class to know exactly how many parameters he has to pass to the function.
You cannot. If it is an override, the signature must be an exact match. If you want different parameters, it doesn't sound like an override - after all... how would a caller call it, knowing just the base type? (substitution principal, etc)
BaseClass obj = GetSomeConcreteObject(); // actually a DerievedClass2
obj.ChangeParameters({what would go here?});
It sounds to me like these are just independent methods. You could have a virtual method that takes an array (with or without params), but then you need to accept that the caller can supply any size.
That's not really possible.
By definition, an override must maintain the same name and set of parameters (aka the signature) as the original method.
How is the runtime supposed to bind your "override" to a method call on the superclass if you are using different parameters? Imagine this were possible:
class A
{
virtual void Foo(int i) { Console.WriteLine(i); }
}
class B : A
{
override void Foo(int i, int j) { Console.WriteLine(i + j); }
}
// somewhere else
void DoSomething(A a)
{
a.Foo(1);
}
// later
DoSomething(new B()); // how will b.Foo get called inside DoSomething?
If you vary the parameters all you get is an overload.
Interesting trick could be done also using optional parameters, like this:
public class Base
{
public virtual void DoSomething(string param="Hello", string param1 = "Bye")
{
Console.WriteLine(string.Format("prm: {0}, prm1: {1}", param, param1));
}
}
public class Derived : Base
{
public override void DoSomething(string param="Ciao", string param1="Ciao")
{
Console.WriteLine(string.Format("prm: {0}, prm1: {1}", param, param1));
}
}
So you can use in code like:
Base a = new Derived();
a.DoSomething();
Output is:
prm: Hello, prm1: Bye
But you can now this:
Base a = new Derived();
a.DoSomething("Ciao");
and output like this:
prm: Ciao, prm1: Bye //!!

Very basic exercise in Virtual functions

Alright, so here's the exercise:
You must define three classes. One class named MyNum that contains a variable of type int. Second class called MyString, will be derived from MyNum and contains string. Third-class call MyType and returns a variable of type MyNum. Each class will be set to a constructor function and virtual function called Show. The constructor function of MyType receive a MyNum variable, whereas the function Show of MyType will run the Show function of MyNum.
Now, you need set two objects of type MyType and initialize them. Once an object type MyNum and once an object of type MyString.
Here's the code:
class MyNum
{
protected int num;
public MyNum(int num)
{
this.num = num;
}
public virtual void Show()
{
Console.WriteLine("The number is : " + num);
}
}
class MyString : MyNum
{
string str;
public MyString(string str)
{
this.str= str;
}
}
class MyType : MyNum
{
MyNum num2;
public MyType(MyNum num)
{
this.num2 = num;
}
public override void Show()
{
base.Show();
}
}
class Program
{
static void Main(string[] args)
{
}
}
I'm having the following error:
Error 1 'ConsoleApplication1.MyNum' does not contain a constructor that takes '0' arguments C:\Users\x\AppData\Local\Temporary Projects\ConsoleApplication1\Program.cs 23 16 ConsoleApplication1
Anyone knows why am I having this error? Thanks.
Since your class subclasses MyNum, it needs to be able to construct it. You don't have a default constructor, so you have to explicitly call it with a value.
For example:
// Since this is here, you're saying "MyType is a MyNum"
class MyType : MyNum
{
MyNum num2;
public MyType(MyNum num) // You need to call the base class constructor
// here to construct that portion of yourself
: base(42) // Call this with an int...
{
this.num2 = num;
}
The class MyString will need similar treatment. It will have to have a constructor that calls the base class constructor, too.
Note that, if the MyNum class had a default constructor (which could be protected), this wouldn't matter. Instead of calling these constructors, the other alternative is to do something like:
class MyNum
{
public MyNum(int num)
{
this.num = num;
}
// Add a default constructor that gets used by the subclasses:
protected MyNum()
: this(42)
{
}
Edit in response to comments:
If you want to override the base class constructor, try:
class MyType : MyNum
{
public MyType(int num)
: base(num)
{
}
public override void Show()
{
Console.WriteLine("The number [MyType] is : " + this.num);
}
}
MyString implicitely has a zero-arg constructor because you did not specify any constructor in that class. You could either declare a zero-arg constructor in the super class or declare a one-arg constructor in MyString.
MyString does not have a constructor, so it will use the one from the base class MyNum, which doesn't have a default one with no parameters.
MyString needs a constructor or you need a paramterless one in the base class.

Categories

Resources