Generic class with overridden method - which gets called? - c#

I have a class that overrides the addition operator twice. One that takes the type parameter and one that takes a double:
public class A<T>
{
public A() { }
public static A<T> operator +(A<T> a, T t)
{
Console.WriteLine("Generic add called.");
return new A<T>(); // return to keep the compiler happy
}
public static A<T> operator +(A<T> a, double d)
{
Console.WriteLine("Double add called.");
return new A<T>(); // return to keep the compiler happy
}
}
When the class is parameterized by the int type, it behaves as expected:
A<int> aInt = new A<int>();
var test = aInt + 3;
// -> Generic add called.
test = aInt + 3.0;
// -> Double add called.
But when parameterized by the double type, the non-generic add is called:
A<double> aDouble = new A<double>();
var otherTest = aDouble + 3.0;
// -> Double add called.
Assuming this behavior is the norm, I know which will be called. The non-generic override will be preferred. That said...
Will the non-generic method be always be preferred in the event of a collision?
All of the above code is available, runnable in your browser, here
EDIT: This question is related, but it's asking about generic methods, not classes. He gives this code:
class A
{
public static void MyMethod<T>(T myVal) { }
public static void MyMethod(int myVal) { }
}
which does not apply to my usage examples. Distinguishing between a.MyMethod(3) and a.MyMethod<int>(3) is obvious - one is generic and one is not.

The more specific method will be chosen, but that construction is a bad idea because it is technically unspecified behaviour.
To quote #EricLippert, substituting the code snippets for the ones from my question:
But the situation with [aDouble + 3.0] is far worse. The CLR rules make this sort of situation "implementation defined behaviour" and therefore any old thing can happen. Technically, the CLR could refuse to verify a program that constructs type [A<double>]. Or it could crash. In point of fact it does neither; it does the best it can with the bad situation.
Are there any examples of this sort of type construction causing truly implementation-defined behaviour?
Yes. See these articles for details:
http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Simple answering yes. The compiler assume that because you have treated by hand a particular type parameter, that means that it has some special logic for you. That's why the second operator is called. To say further, operators are nothing more than static methods that accepts some parameters. For your case it's a binary operator so the static method has two parameters.

Related

Disambiguate between two constructors, when two type parameters are the same

Given
class Either<A, B> {
public Either(A x) {}
public Either(B x) {}
}
How to disambiguate between the two constructors when the two type parameters are the same?
For example, this line:
var e = new Either<string, string>("");
Fails with:
The call is ambiguous between the following methods or properties: 'Program.Either.Either(A)' and 'Program.Either.Either(B)'
I know if I had given the parameters different names (e.g. A a and B b instead of just x), I could use named parameters to disambiguate (e.g. new Either<string, string>(a: "")). But I'm interested in knowing how to solve this without changing the definition of Either.
Edit:
You can write a couple of smart constructors, but I'm interested in knowing if the Either's constructors can be called directly without ambiguity. (Or if there are other "tricks" besides this one).
static Either<A, B> Left<A, B>(A x) {
return new Either<A, B>(x);
}
static Either<A, B> Right<A, B>(B x) {
return new Either<A, B>(x);
}
var e1 = Left<string, string>("");
var e2 = Right<string, string>("");
How to disambiguate between the two constructors when the two type parameters are the same?
I'll start by not answering your question, and then finish it up with an actual answer that lets you work around this problem.
You don't have to because you should never get yourself into this position in the first place. It is a design error to create a generic type which can cause member signatures to be unified in this manner. Never write a class like that.
If you go back and read the original C# 2.0 specification you'll see that the original design was to have the compiler detect generic types in which it was in any way possible for this sort of problem to arise, and to make the class declaration illegal. This made it into the published specification, though that was an error; the design team realized that this rule was too strict because of scenarios like:
class C<T>
{
public C(T t) { ... }
public C(Stream s) { ... deserialize from the stream ... }
}
It would be bizarre to say that this class is illegal because you might say C<Stream> and then be unable to disambiguate the constructors. Instead, a rule was added to overload resolution which says that if there's a choice between (Stream) and (T where Stream is substituted for T) then the former wins.
Thus the rule that this kind of unification is illegal was scrapped and it is now allowed. However it is a very, very bad idea to make types that unify in this manner. The CLR handles it poorly in some cases, and it is confusing to the compiler and the developers alike. For example, would you care to guess at the output of this program?
using System;
public interface I1<U> {
void M(U i);
void M(int i);
}
public interface I2<U> {
void M(int i);
void M(U i);
}
public class C3: I1<int>, I2<int> {
void I1<int>.M(int i) {
Console.WriteLine("c3 explicit I1 " + i);
}
void I2<int>.M(int i) {
Console.WriteLine("c3 explicit I2 " + i);
}
public void M(int i) {
Console.WriteLine("c3 class " + i);
}
}
public class Test {
public static void Main() {
C3 c3 = new C3();
I1<int> i1_c3 = c3;
I2<int> i2_c3 = c3;
i1_c3.M(101);
i2_c3.M(102);
}
}
If you compile this with warnings turned on you will see the warning I added explaining why this is a really, really bad idea.
No, really: How to disambiguate between the two constructors when the two type parameters are the same?
Like this:
static Either<A, B> First<A, B>(A a) => new Either<A, B>(a);
static Either<A, B> Second<A, B>(B b) => new Either<A, B>(b);
...
var ess1 = First<string, string>("hello");
var ess2 = Second<string, string>("goodbye");
which is how the class should have been designed in the first place. The author of the Either class should have written
class Either<A, B>
{
private Either(A a) { ... }
private Either(B b) { ... }
public static Either<A, B> First(A a) => new Either<A, B>(a);
public static Either<A, B> Second(B b) => new Either<A, B>(b);
...
}
...
var ess = Either<string, string>.First("hello");
The only way I could think of would be to use reflection to iterate each constructor and then determine which one should be used based on the method body.
Of course this is way over the top and you should really just refactor your class, but it is a working solution.
It requires that you identify the byte[] for the method body that you want to use and 'hard code' that into the program (or read from file etc.). Of course you need to be very cautious that the method body may change over time, for example if the class is modified at any point.
// You need to set (or get from somewhere) this byte[] to match the constructor method body you want to use.
byte[] expectedMethodBody = new byte[] { 0 };
Either<string, string> result = null; // Will hold the result if we get a match, otherwise null.
Type t = typeof(Either<string, string>); // Get the type information.
// Loop each constructor and compare the method body.
// If we find a match, then we invoke the constructor and break the loop.
foreach (var c in t.GetConstructors())
{
var body = c.GetMethodBody();
if (body.GetILAsByteArray().SequenceEqual(expectedMethodBody))
{
result = (Either<string, string>)c.Invoke(new object[] { "123" });
break;
}
}
Disclaimer: Although I have tested this code briefly and it seems to work, I am really sceptical about how reliable it is. I do not know enough about the compiler to be comfortable in saying the method body wont change on a re-compile even if the code isn't changed. It may be that it would become more reliable if this class was defined in a pre-compiled DLL, again I don't know for sure though.
There may be other information you could get via reflection that might make it easier to identify the correct constructor. However, this was the first that came to mind and I haven't really looked into any other possible options at this time.
It would be much simpler if we could rely on the order of the constructors, but as quoted from MSDN, it is not reliable:
The GetConstructors method does not return constructors in a particular order, such as declaration order. Your code must not depend on the order in which constructors are returned, because that order varies.

Why is method overloading not working in this C# program?

namespace test
{
class Program
{
static void Main(string[] args)
{
Derived obj = new Derived();
int i = 10;
obj.Foo(i);
Console.ReadLine();
}
}
class Base
{
public virtual void Foo(int i)
{
Console.WriteLine("Base:Foo()");
}
}
class Derived:Base
{
public override void Foo(int i)
{
Console.WriteLine("Foo(int)");
}
public void Foo(object i)
{
Console.WriteLine("Foo(object)");
}
}
}
output of the program according to me should be Foo(int) but output is coming as Foo(object) please help me in understanding the diffrence in output
Good question, I can reproduce your results. If one takes a look at the C# specifications one will find the following snippets:
7.5.3 Overload resolution
For example, the set of candidates for a method invocation does not
include methods marked override (§7.4), and methods in a base class
are not candidates if any method in a derived class is applicable
(§7.6.5.1).
7.4 Member Lookup
Otherwise, the set consists of all accessible (§3.5) members named N
in T, including inherited members and the accessible members named N
in object. If T is a constructed type, the set of members is obtained
by substituting type arguments as described in §10.3.2. Members that
include an override modifier are excluded from the set.
7.6.5.1 Method invocations
The set of candidate methods is reduced to contain only methods from
the most derived types: For each method C.F in the set, where C is the
type in which the method F is declared, all methods declared in a base
type of C are removed from the set. Furthermore, if C is a class type
other than object, all methods declared in an interface type are
removed from the set.
Sounds a bit complicated? Even the C# designers seem to think so and put in the 'helpful' note:
7.6.5.1 Method invocations
The intuitive effect of the resolution rules described above is as
follows: To locate the particular method invoked by a method
invocation, start with the type indicated by the method invocation and
proceed up the inheritance chain until at least one applicable,
accessible, non-override method declaration is found. Then perform
type inference and overload resolution on the set of applicable,
accessible, non-override methods declared in that type and invoke the
method thus selected. If no method was found, try instead to process
the invocation as an extension method invocation.
If we take a look at your derived class, we see two possible methods for C# to use:
A) public override void Foo(int i)
B) public void Foo(object i)
Let's use that last checklist!
Applicability - Both A and B are applicable -(both are void, both are named 'Foo' and both can accept an integer value).
Accessibility - Both A and B are accessible (public)
Not Overridden - Only B is not overridden.
But wait you might say! A is more specific than B!
Correct, but that consideration is only made after we've disregarded option A. As Eric Lippert (one of the designers) puts it Closer is always better than farther away. (Thanks Anthony Pegram)
Addendum
There is always the 'new' keyword:
class Derived : Base
{
public new void Foo(int i)
{
Console.WriteLine("Foo(int)");
}
public void Foo(object i)
{
Console.WriteLine("Foo(object)");
}
}
Though the specifics of that best left for another question!
The simple datatype int descends from object. You are overriding the function and also overloading the parameter list. Since the function name is the same with a different signature the compiler allows this. For simple objects, I image one copy of the parameter signature in the most basic form is stored in the method table.

Delegates with same signature

My question is a bit similar to this one: How to convert an action to a defined delegate of the same signature?
Why there is no implicit convertion between delegates with same signature. For example, code:
class Program
{
private delegate void Foo1(int x);
private delegate void Foo2(int x);
static void Main(string[] args)
{
Foo1 foo1 = Console.WriteLine;
Foo2 foo2 = Console.WriteLine;
Call(foo1);
Call2(foo2);
}
static void Call(Action<int> action)
{
action(10);
}
static void Call2(Foo1 action)
{
action(10);
}
}
it does not compile because there isn't implicit convertion from Action<int> to Foo1.
But normaly it's the same thing. So it mean this names are aliases, not actualy names. So i think it was great idea to think about it like aliases. So in this case we have 3 aliases of a delegate, that get one int value and returns nothing. And this delegates are fully interchangeable one by another. But we don't have it. So question is: why? By signatures it's the same thing, and there isn't any implementation, so delegates with same signature are one and same with many aliases...
Is it C# defect or there are reasons for it? As to me, i don't see any.
There's no implicit conversion between those two delegates for the same reason that there's no implicit conversion between these two types:
public sealed class Foo1
{
public string Value { get; set; }
}
public sealed class Foo2
{
public string Value { get; set; }
}
Just because two classes have the same fields doesn't mean that you should be able to treat one as if it were another. The same logic applies to delegates (which are also types, mind you).
There is semantic meaning applied to the creation of that type. If someone created a Foo1 they want it to be a Foo1, not a Foo2. If they're going out of their way to use a Foo1 where a Foo2 is expected, it's a big red flag that even though the types appear similar, there is a semantic difference between these two types. If the programmer knows something that the compiler doesn't, they can use an explicit conversion of some sort to indicate that they know what they're doing.
(The previous paragraph was intentionally written to apply equally to your delegates, and the classes I provided above.)

How to call overridden method which have overloads?

I have the following simple code
abstract class A
{
public abstract void Test(Int32 value);
}
class B : A
{
public override void Test(Int32 value)
{
Console.WriteLine("Int32");
}
public void Test(Double value)
{
Test((Int32)1);
}
}
When I ran this code the line Test((Int32)1) causes stack overflow due to infinite recursion. The only possible way to correctly call proper method (with integer parameter) I found is
(this as A).Test(1);
But this is not appropriate for me, because both methods Test are public and I am willing the users to be able to call both method?
Method overload resolution in C# does not always behave as you might expect, but your code is behaving according to the specification (I wrote a blog post about this a while ago).
In short, the compiler start off by finding methods that
Has the same name (in your case Test)
are declared in the type (in your case B) or one of its base types
are not declared with the override modifier
Note that last point. This is actually logical, since virtual methods are resolved in run-time, not compile time.
Finally, if the type (in this case B) has a method that is a candidate (which means that the parameters in your call can be implicitly converted to the parameter type of the candidate method), that method will be used. Your overridden method is not even part of the decision process.
If you want to call your overridden method, you will need to cast the object to its base type first.
Unfortunately in order to call the A::Test(int) through a B reference some sort of cast is needed. So long as the C# compiler sees the reference through B it will pick the B::Test(double) version.
A slightly less ugly version is the following
((A)this).Test(1);
Another thought though is have a private method with a different name that both feed into.
class B : A {
public override void Test(int i) {
TestCore(i);
}
public void Test(double d) {
TestCore(1);
}
private void TestCore(int i) {
// Combined logic here
}
}

C# Method Resolution, long vs int

class foo
{
public void bar(int i) { ... };
public void bar(long i) { ... };
}
foo.bar(10);
I would expect this code to give me some error, or at least an warning, but not so...
What version of bar() is called, and why?
The int version of bar is being called, because 10 is an int literal and the compiler will look for the method which closest matches the input variable(s). To call the long version, you'll need to specify a long literal like so: foo.bar(10L);
Here is a post by Eric Lippert on much more complicated versions of method overloading. I'd try and explain it, but he does a much better job and I ever could: http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
from the C# 4.0 Specification:
Method overloading permits multiple
methods in the same class to have the
same name as long as they have unique
signatures. When compiling an
invocation of an overloaded method,
the compiler uses overload resolution
to determine the specific method to
invoke. Overload resolution finds the
one method that best matches the
arguments or reports an error if no
single best match can be found. The
following example shows overload
resolution in effect. The comment for
each invocation in the Main method
shows which method is actually
invoked.
class Test {
static void F() {
Console.WriteLine("F()");
}
static void F(object x) {
Console.WriteLine("F(object)");
}
static void F(int x) {
Console.WriteLine("F(int)");
}
static void F(double x) {
Console.WriteLine("F(double)");
}
static void F<T>(T x) {
Console.WriteLine("F<T>(T)");
}
static void F(double x, double y) {
Console.WriteLine("F(double,double)");
}
static void Main() {
F(); // Invokes F()
F(1); // Invokes F(int)
F(1.0); // Invokes F(double)
F("abc"); // Invokes F(object)
F((double)1); // Invokes F(double)
F((object)1); // Invokes F(object)
F<int>(1); // Invokes F<T>(T)
F(1, 1); // Invokes F(double, double)
}
}
As shown by the example, a particular
method can always be selected by
explicitly casting the arguments to
the exact parameter types and/or
explicitly supplying type arguments.
As Kevin says, there's an overload resolution process in place. The basic sketch of the process is:
Identify all the accessible candidate methods, possibly using type inference on generic methods
Filter out the inapplicable methods; that is, the methods that cannot work because the arguments don't convert implicitly to the parameter types.
Once we have a set of applicable candidates, run more filters on them to determine the unique best one.
The filters are pretty complicated. For example, a method originally declared in a more derived type is always better than a method originally declared in a less derived type. A method where the argument types exactly match the parameter types is better than one where there are inexact matches. And so on. See the specification for the exact rules.
In your particular example the "betterness" algorithm is straightforward. The exact match of int to int is better than the inexact match of int to long.
I would say if you exceed below limit
-2,147,483,648 to 2,147,483,647
control will go to long
Range for long
–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Max value for int
foo.bar(-2147483648);
or
foo.bar(2147483648);
Long will get control if we exceed the value by 2147483648

Categories

Resources