Different behaviour of overlaoded method call if method is overriden - c#

I have two overloaded methods MyMethod. One with an int as parameter the other with a long.
Calling this method from outside with a integer calls the MyMethod(int) member. But if the method with int is overridden then the MyMethod(long) is called. I do not understand why dot.net behaves like this. Can someone explain the technical background?
For me it looks like a bug.
Example 1. and 3. (see code below) behaves like I would expect. But the 2. one I cannot explain why the code calls the long method.
// 1. Normal Overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyClass().MyMethod(value);
// Output: Method INT
Console.ReadKey();
}
}
class MyClass
{
public void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}
// 2. Combine Overriding with Overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyChildClass1().MyMethod(value);
// Output: Method LONG
Console.ReadKey();
}
}
class MyParentClass
{
public virtual void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
}
class MyChildClass1 : MyParentClass
{
public override void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}
// 3. Inherit but use New for overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyChildClass2().MyMethod(value);
// Output: Method INT
Console.ReadKey();
}
}
class MyParentClass
{
public virtual void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
}
class MyChildClass2 : MyParentClass
{
public new void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}

It's not a bug, it's a planned behavior (but I agree this is a bit of confusing especially in comparison with others examples). From here:
There's one aspect of this behaviour which is particularly surprising though. What counts as a method being "declared" in a class? It turns out that if you override a base class method in a child class, that doesn't count as declaring it.

Related

Method call with C# dynamic in inherited type

I have noticed an unexpected behavior while trying to extend a base class. Here is a sample for this problem:
public class Program
{
static void Main(string[] args)
{
var test = new CoolProgram();
test.Start();
}
private void Start()
{
var arr = new object[]
{
1, // int
1L, // long
"Hello World" // string
};
foreach (var dyn in arr.Cast<dynamic>())
{
DoSomething(dyn);
}
Console.ReadKey();
}
protected virtual void DoSomething(int i)
{
Console.WriteLine("Int:" + i);
}
protected virtual void DoSomething(string str)
{
Console.WriteLine("Str:" + str);
}
}
The Program defines two methods DoSomething which are overloaded by int and string arguments. The Start method creates an array of objectwhich contains boxed values. After the definition, the elements will be iterated with casteddynamic`. This works fine so far (without the long value).
If I create an additional inherited class CoolProgram and add another method to the type for long the program will throw an RuntimeBinderException and tells me that the best overload was DoSomething(int). The method of CoolProgram was not executed.
public class CoolProgram : Program
{
protected override void DoSomething(int i)
{
// This works
Console.WriteLine("Cool Int: " + i);
}
protected override void DoSomething(string str)
{
// This works
Console.WriteLine("Cool Str: " + str);
}
protected virtual void DoSomething(long i)
{
// This is a new method for long
Console.WriteLine("Long:" + i);
}
}
Can anybody explain this behavior or have a solution for it?
Your example can be simplified further:
static void Main(string[] args)
{
Program test = new CoolProgram();
dynamic i = 1L;
test.DoSomething(i);
//test.Start();
}
The issue is that as far as the Start() method is concerned, this has the type Program. Adding a virtual overload for DoSomething() means nothing in the context of the Start() method.
Likewise in my simplified example above. The compile-time type of test is Program, just as the type of this in Start() is Program. Thus, the DoSomething(long) overload is not visible in that context, and can't be called.
If you want it to be visible, you need to either add it to the base class, or make sure that the reference used to call DoSomething() is statically typed as CoolProgram. Note that since the method is declared as protected in CoolProgram, you'd also have to change the accessibility, if you want to go the route of changing the static type of the reference to CoolProgram.
Finally, if you really want fully dynamic type resolution here, you can:
private void Start()
{
dynamic this2 = this;
var arr = new object[]
{
1, // int
1L, // long
"Hello World" // string
};
foreach (var dyn in arr.Cast<dynamic>())
{
this2.DoSomething(dyn);
}
Console.ReadKey();
}
The above would of course require that DoSomething(long) be made public, as I noted above.
1)first issue is access modifier protected due to which you are not able to access the overloaded method with Long type as a parameter. i changed it to internal now it is accessible.
2) The second issue is you are creating child class CoolProgram object but you are calling parent class DoSomething method you should use test.DoSomething(dyn); and make the child class object global to access it in your Start method.
public class Program
{
static CoolProgram test;
static void Main(string[] args)
{
test = new CoolProgram();
test.Start();
}
private void Start()
{
var arr = new object[]
{
1, // int
1L, // long
"Hello World" // string
};
//test.DoSomething(21474836470);
foreach (var dyn in arr.Cast<dynamic>())
{
test.DoSomething(dyn);
}
Console.ReadKey();
}
protected virtual void DoSomething(int i)
{
Console.WriteLine("Int:" + i);
}
protected virtual void DoSomething(string str)
{
Console.WriteLine("Str:" + str);
}
}
// from here child class
public class CoolProgram : Program
{
protected override void DoSomething(int i)
{
// This works
Console.WriteLine("Cool Int: " + i);
base.DoSomething(i);
}
protected override void DoSomething(string str)
{
// This works
Console.WriteLine("Cool Str: " + str);
}
internal virtual void DoSomething(long i)
{
// This is a new method for long
Console.WriteLine("Long Int:" + i);
}
}

Interface particular properties

How to solve this problem about interfaces? I think I need this variable (and some others)in this especific class.
public interface Action
{
void execute();
}
public A:Action
{
public int misteriousNumber;
void execute()
{
int iUseMisteriousNumber = misteriousNumber;
}
}
public B:Action
{
void execute()
{
//I use nothing.
}
}
//Some Class...
static void Main(string[] args)
{
foreach(Action action in SecretRepositoryOfTheActions.actions)
{
if(action is A)
(SomeTypeOfCasting to A)action.misteriousNumber=13;
action.execute();
}
}
Just the 'A' class have this property not other Action classes what to use to access it (casting, not interfaces other implementation)?
You have to cast it, first check the type with is:
foreach(Action action in SecretRepositoryOfTheActions.actions)
{
if(action is A)
((A) action).misteriousNumber = 13;
action.execute();
}
If you only wanted to process A-objects (which doesn't seem to be the case):
foreach(A a in SecretRepositoryOfTheActions.actions.OfType<A>())
{
a.misteriousNumber = 13;
a.execute();
}

Calling functions when parameter is value or reference type in C#?

public class A
{
void methodA(int a){}
void methodA(ref int a){}
}
static void Main()
{
int a=1;
new classA().methodA(a);
}
In Main class, which method is called? Are methods in class A are overloaded? can overriding is possible on the bases of value or reference parameters? Please help out to make me clear.
After fixing your code:
public class ClassA
{
public void methodA(int a)
{
Console.WriteLine("Without ref");
}
public void methodA(ref int a)
{
Console.WriteLine("With ref");
}
}
class Program
{
static void Main(string[] args)
{
int i = 1;
var a = new ClassA();
a.methodA(i);
a.methodA(ref i);
Console.ReadKey(true);
}
}
You'll see that the first call will print 'Without ref' and the second 'With ref'. You could've done this yourself.
The manual says it's perfectly possible:
However, overloading can be done when one method has a ref or out parameter and the other has a value parameter, as shown in the following example.
class RefOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(ref int i) { }
}
new A().methodA(a);
will call the non-ref version.
new A().methodA(ref a);
will call the ref version.
In C#, you have to explicitly say if you're passing by reference.
Following calls are different
int a = 5;
methodA(a);
methodA(ref a );
ref keyword MSDN
overloading can be done when one method has a ref or out parameter and
the other has a value parameter, as shown in the following example
In your case it will call methodA(int a){} not the one with ref.
Your class should be:
public class A
{
public void methodA(int a)
{
}
public void methodA(ref int a)
{
}
}
If you want to call the overloaded method with ref keyword you need to specify ref in your method call. Like:
int a = 1;
A classAObj = new A();
classAObj.methodA(ref a);
The above code will resolved to the overloaded methodA(ref a)
public class A
{
void methodA(int a){}
void methodA(ref int a){}
}
static void Main()
{
int a=1;
new classA().methodA(a);
new classA().methodA(ref a)//You can add this to see the difference
}
Both are different from each other...
new classA().methodA(a);
new classA().methodA(ref a)

How to call a Method from String using c#? [duplicate]

This question already has answers here:
Calling a function from a string in C#
(5 answers)
Closed 1 year ago.
I have created a class library, which has 4 classes each class have 1 method.
First class is the main class for me, in my first class, i have a string called calltoaction, in this string i will be getting the one of below list dynamically
class2.Method2()
class3.Method3()
class4.Method4()
now i want to execute the "class2.method2" from the string "calltoaction".
Say for ex:
class Class1
{
public void method1()
{
string calltoaction = "Class2.Method2()";
}
}
How to execute the "Class2.Method" from the string?
I'm not entirely sure what you are trying to accomplish, but I am sure it can be done in a better way. Basically, if I understand your question correctly, calling this function returns the name of a class and method that you wish to execute.
If that is the case, I would drop the whole "string" thing indefinitely and start looking at delegates.
Consider this:
public class Class2
{
public static void Method2() { }
} // eo class 2
public class Class3
{
public static void Method3() { }
} // eo class 3
public class Class4
{
public static void Method4() { }
} // eo class 4
Now we'd come to our main class
public class MainClass
{
private delegate void MethodDelegate();
private List<MethodDelegate> delegates_ = new List<MethodDelegate>();
// ctor
public MainClass()
{
delegates_.Add(Class2.Method2);
delegates_.Add(Class3.Method3);
delegates_.Add(Class4.Method4);
}
// Call a method
public void Method1()
{
// decide what you want to call:
delegates_[0].Invoke(); // "Class2.Method2"
} // eo Method1
} // eo class Main
Use an Action instead of a string (Assuming you don't need a return value. If you do - use Func):
This is for an idea of how to use it:
public Form1()
{
InitializeComponent();
Action<string> calltoaction;
calltoaction = Doit;
calltoaction("MyText1");
calltoaction = Doit2;
calltoaction("MyText2");
}
void Doit(string s)
{ Text = s; }
void Doit2(string s)
{ textBox1.Text = s; }
I guess a low tech way would be to use a switch statement like so:
using System;
namespace ConsoleApplication24
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Which method would you like to run?");
RunMyMethod(Console.ReadLine());
}
private static void RunMyMethod(string p)
{
switch (p)
{
case "MethodOne();":
MethodOne();
break;
case "MethodTwo();":
MethodTwo();
break;
case "MethodThree();":
MethodThree();
break;
}
}
private static void MethodThree()
{
//Do Stuff
}
private static void MethodTwo()
{
//Do Stuff
}
private static void MethodOne()
{
//Do Stuff
}
}
}

How to convert an action to a defined delegate of the same signature?

class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del; // Cannot implicitly convert type 'Action<T>' to 'FruitDelegate
}
}
Fruit is an empty class. Both of these delegates have the same signature.
I cannot seem to get any of this working. Maybe it would help if I explained what I am trying to do (provide some context).
I want to create a class that has a generic static method that provides a type and a method callback (like the above example).
The problem I am having is that the delegate contains a parameter and I don't want to have to cast it within the method callback. For example, I want this:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Apple apple)
{
}
Instead of this:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Fruit fruit)
{
Apple apple = (Apple)fruit;
}
Is this kind of thing possible?
is this what you want?
static void Main(string[] args)
{
Program p = new Program();
p.SomeMethod();
}
public class Fruit
{ }
public class Apple : Fruit { }
public delegate void FruitDelegate<in T>(T f) where T : Fruit;
class Test
{
public static void Notify<T>(FruitDelegate<T> del)
where T : Fruit, new()
{
T t = new T();
del.DynamicInvoke(t);
}
}
private void AppleHandler(Apple apple)
{
Console.WriteLine(apple.GetType().FullName);
}
public void SomeMethod()
{
FruitDelegate<Apple> del = new FruitDelegate<Apple>(AppleHandler);
Test.Notify<Apple>(del);
}
There is good reason you cannot do this. Suppose the rest of your method was:
class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del;
f(new Banana()); //should be legal, but del may be Action<Apple>
}
}
That would definitely not work, so the compiler is correct here.
What about something like this?
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = fruit => del((T)fruit);
}
The FruitDelegate instance, when invoked, would throw an InvalidCastException if, say, an AppleHandler was invoked with a Banana argument.

Categories

Resources