I was suprised when found that the following code throws exception at runtime:
class A
{
public string Name { get; set; }
public A()
{
Name = "Class A";
}
}
class B
{
public string Name { get; set; }
public B()
{
Name = "Class B";
}
public static explicit operator A(B source)
{
return new A() {Name = source.Name};
}
}
class Program
{
static void Main(string[] args)
{
// This executes with no error
var bInstance = new B();
Console.WriteLine(bInstance.GetType()); // <assemblyname>.B
var aInstance = (A) bInstance;
Console.WriteLine(aInstance.Name); // Class B
// This fails with InvalidCastException
var bInstanceReflection = Activator.CreateInstance(typeof (B));
Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
var aInstanceReflection = (A) bInstanceReflection;
Console.WriteLine(aInstanceReflection.Name);
}
}
Could anyone tell me why? I don't really understand what happened
You shouldn't be surprised - custom operators don't override anything, they overload - so they're picked at compile time, not execution time.
When we remove implicit typing from the code, it makes it a bit clearer:
object bInstanceReflection = Activator.CreateInstance(typeof (B));
Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
A aInstanceReflection = (A) bInstanceReflection;
Now it's reasonably clear that in the final line, (A) is just a cast from object which performs the normal reference conversion. No user-defined conversions will be applied at all.
If you're using .NET 4, you can use dynamic typing to get it to work:
// Note the change of type
dynamic bInstanceReflection = Activator.CreateInstance(typeof (B));
Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
A aInstanceReflection = (A) bInstanceReflection;
Now the conversion is being applied on a dynamic value, which means the choice of what conversion to use is deferred until execution time - at which point it will use your custom operator.
You've created a B. And then cast it to an A.
Despite having similar layouts, B has no relationship to A. Static operators are applied by the compiler, but not at runtime via cast. Although the C# syntax is the same, they are very different when dealing with reflection.
This is the normal, expected behaviour.
You can simply change this line:
var bInstanceReflection = Activator.CreateInstance(typeof (B));
To:
var bInstanceReflection = (B)Activator.CreateInstance(typeof (B));
So the compiler now knows the type of bInstanceReflection and can call the correct implitic operator.
Related
I am getting a RuntimeBinderException with the message
Cannot implicitly convert type 'object' to 'MyNamespace.SomeEnum?'. An explicit conversion exists (are you missing a cast?)
The following code generates that error:
public enum SomeEnum
{
Val1
}
public class Example
{
public SomeEnum? EnumMember { get; set; }
}
public static class Program
{
static void Main()
{
dynamic example = new Example();
// Works without issue
example.EnumMember = (dynamic)Enum.Parse(typeof(SomeEnum), "Val1");
// Works without issue
example.EnumMember = Enum.Parse(example.EnumMember.GetType(), "Val1");
// Throws the aforementioned RuntimeBinderException
example.EnumMember = Enum.Parse(typeof(SomeEnum), "Val1");
}
}
Why do to first two lines work (both return type dynamic), but the third throws an exception (when the return type is object)? I was under the impression that, when assigning to dynamic, the binding is performed using the actual, run-time type of the right-hand-side. Can someone please enlighten me as to why the third line is unable to run as written?
The compile-time type of the expression on the RHS of the = operator for the first two lines is dynamic. In the first case that's because you've cast to dynamic, and in the second case it's because you're using a dynamic value in one of the arguments.
In the third case, the compile-time type of the expression is object. So you're trying to do the equivalent of:
object x = Enum.Parse(typeof(SomeEnum), "Val1");
example.EnumMember = x;
That doesn't work, because there's no implicit conversion from object to SomeEnum?, which is what the compiler is trying to find at execution time.
Note that the nullability part really isn't relevant here - nor is the fact that it's an enum. It's just that the assignment operator is being bound dynamically, but using the compile-time time of the RHS. Here's a similar but simpler example:
class Test
{
public int Foo { get; set; }
static void Main()
{
dynamic example = new Test();
example.Foo = 10; // Fine
object o = 10;
example.Foo = o; // Bang
}
}
If you want the compiler to handle the assignment dynamically using the actual type of the value returned rather than the compile-time type, then using dynamic is exactly what you want to do - either cast to dynamic, or use:
dynamic value = ...;
target.SomeProperty = value;
You still need to do an implicit conversion for the third line
example.EnumMember = (SomeEnum) Enum.Parse(typeof(SomeEnum), "Val1");
EDIT
The reason that you still need implicit conversion is because Enum.Parse returns an object. Refer to the documentation below.
https://msdn.microsoft.com/en-us/library/essfb559(v=vs.110).aspx
According to the answer to C#: Passing null to overloaded method - which method is called?, nulls seem to carry type information. In fact, I can also use
class Program
{
static void Method(TypeA a)
{
Console.Write("Output of Method(TypeA a):");
Console.WriteLine(a); // Prints nothing, on account of the null.
}
static void Method(TypeB b)
{
Console.Write("Output of Method(TypeB b):");
Console.WriteLine(b); // Also prints nothing, on account of the null.
}
static void Main()
{
var a = (TypeA)null;
var b = (TypeB)null;
Method(a);
Method(b);
}
}
class TypeA { }
class TypeB { }
Which yields
Output of Method(TypeA a): Output of Method(TypeB b):
What's going on here?
No, the null itself doesn't carry the type information. The cast just tells the compiler what the type of the variables a and b should be... it can't tell without the cast, because null is convertible to any reference type or nullable type.
The types of those variables are then used in overload resolution. Don't forget that the choice here is simply made at compile-time - it doesn't involve the execution-time value of the argument at all.
Your code is precisely equivalent to:
TypeA a = null;
TypeB b = null;
Method(a);
Method(b);
If you used dynamic typing, so that the overload resolution was performed at execution-time instead, you'd get a failure:
dynamic foo = (TypeA) null; // Or without the cast. It makes no difference.
Method(foo); // RuntimeBinderException at execution time, due to ambiguity
While the case presented is obvious, I stumbled upon some odd behaviour involving dynamic casts. Have a look at the program below:
class Base { }
class Child : Base { }
class Program
{
static void Main(string[] args)
{
Base node = GetChild();
Test((dynamic) node);
node = GetBase();
Test((dynamic) node);
}
static Child GetChild()
{
return null;
}
static Base GetBase()
{
return null;
}
// Guess how many times each method is called..
static void Test(Base node)
{
// Nope!
}
static void Test(Child child)
{
// It's this one twice.
}
}
Inspecting the code with .NET reflector resulted in a crash (Ambiguous Match), but dotPeek provided a closer look at the generated IL (decompiled here):
private static void Main(string[] args)
{
Base base1 = (Base) Program.GetChild();
if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Test", (IEnumerable<Type>) null, typeof (Program), (IEnumerable<CSharpArgumentInfo>) new CSharpArgumentInfo[2]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, (string) null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, (string) null)
}));
Program.<Main>o__SiteContainer0.<>p__Site1.Target((CallSite) Program.<Main>o__SiteContainer0.<>p__Site1, typeof (Program), (object) base1);
Base base2 = Program.GetBase();
if (Program.<Main>o__SiteContainer0.<>p__Site2 == null)
Program.<Main>o__SiteContainer0.<>p__Site2 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Test", (IEnumerable<Type>) null, typeof (Program), (IEnumerable<CSharpArgumentInfo>) new CSharpArgumentInfo[2]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, (string) null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, (string) null)
}));
Program.<Main>o__SiteContainer0.<>p__Site2.Target((CallSite) Program.<Main>o__SiteContainer0.<>p__Site2, typeof (Program), (object) base2);
}
I kind of understand the dynamic call site construction, and the fact that two variables are used (base1 and base2) while the source uses only one could be due to optimization. However, that base2 variable has nothing to do with the Child type! It is declared as a variable of type Base and initialized with null from a function with Base prototype.
Adding another class and handler method does what you might or might not expect by throwing a runtime exception "The call is ambiguous between the following methods or properties: 'Program.Test(Child)' and 'Program.Test(AnotherChild)'". This exception is thrown on both the first and the second dynamic cast, which is to be expected as it is similar code.
class AnotherChild : Base { }
static void Test(AnotherChild child)
{
// Ambiguous between AnotherChild and Child -> Runtime Exception
}
In other words, it seems that regardless of type, a dynamic cast on a null object will traverse the inheritance tree bottom-up and gives up when it finds multiple types on that level.. As a conformation of the above, having AnotherChild inherit from Child indeed does invoke the AnotherChild handler.
class AnotherChild : Child { }
To be honest I think it should be illegal to do a dynamic cast on a null object, would be much better if that threw every time. When you're doing dynamic casts you're likely also using method overloads; this just seems like a silent killer in the making.
When you write var, the compiler is determining what type the variable is based on what you are assigning it.
By doing an explicit (C-Style) cast, you are saying "This is what this type is" and var picks that up, causing the overloads to work as displayed.
Assigning "null" is a valid value for any reference type (so of course that compiles), but the type information is provided by the cast.
nulls seem to carry type information
No, the variable has a type. null is just null. Which method is called is determined at compile-time. When you do this:
var a = (TypeA)null;
var b = (TypeB)null;
Method(a);
Method(b);
The compiler binds Method(a) to Method(TypeA) because you use a varaible of type TypeA in the call. Same goes for Method(b). The question you reference explains the binding in better detail.
To prove that null carries no type information, add a third call that defers the method binding to run-time:
static void Main()
{
var a = (TypeA)null;
var b = (TypeB)null;
dynamic c = a;
Method(a);
Method(b);
Method(c); // will throw a `RuntimeBinderException` since the type of c can't be determined at run-time.
}
I have a class Thing that is implicitly castable from a string. When I call a method with a Thing parameter directly the cast from string to Thing is done correctly.
However if I use reflection to call the same method it throws the exception
System.ArgumentException : Object of type 'System.String' cannot be
converted to type 'Things.Program+Thing'.
Maybe there is a good reason for this, but I can't figure it out. Does somebody have an idea how to get this working using reflection?
namespace Things
{
class Program
{
public class Thing
{
public string Some;
public static implicit operator Thing(string s)
{
return new Thing {Some = s};
}
}
public void showThing(Thing t)
{
Console.WriteLine("Some = " + t.Some);
}
public void Main()
{
showThing("foo");
MethodInfo showThingReflected = GetType().GetMethod("showThing");
showThingReflected.Invoke(this, new dynamic[] {"foo"});
}
}
}
Meta: Please, no discussions why implicit casting or reflection is bad.
The trick is to realize that the compiler creates a special static method called op_Implicit for your implicit conversion operator.
object arg = "foo";
// Program.showThing(Thing t)
var showThingReflected = GetType().GetMethod("showThing");
// typeof(Thing)
var paramType = showThingReflected.GetParameters()
.Single()
.ParameterType;
// Thing.implicit operator Thing(string s)
var converter = paramType.GetMethod("op_Implicit", new[] { arg.GetType() });
if (converter != null)
arg = converter.Invoke(null, new[] { arg }); // Converter exists: arg = (Thing)"foo";
// showThing(arg)
showThingReflected.Invoke(this, new[] { arg });
Found an answer which uses a TypeConverter (as Saeed mentions)
Seems to do the job.
TypeConverter For Implicit Conversion when using reflection
In this specific case you can make the conversion through the array type, that is
showThingReflected.Invoke(this, new Thing[] {"foo"});
but that's a kind of "cheating". In general, you cannot expect the Invoke to consider your user-defined implicit operator. This conversion must be inferred compile-time.
I have a generic class NamedValue<TValue>:
public class NamedValue<TValue>
{
public string Name { get; set; }
public TValue Value { get; set; }
}
I have a second generic class, NamedValueSource<TValue> that contains a List<NamedValue<TValue>>:
public class NamedValueSource<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }
public NamedValueSource()
{
NamedValues = GetNamedValues().Cast<NamedValue<TValue>>().ToList();
}
private IEnumerable<NamedValue<bool>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return yesNamedValue;
yield return noNamedValue;
}
}
The following test code works perfectly (the assertion passes):
public class Tester
{
public Tester()
{
var source = new NamedValueSource<bool>();
Debug.Assert(source.NamedValues[0].Name == "Yes");
}
}
Now, here's the interesting part. If I attempt to perform the cast within GetNamedValues(), the code won't compile:
public class NamedValueSourceFail<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }
public NamedValueSourceFail()
{
NamedValues = GetNamedValues().ToList();
}
private IEnumerable<NamedValue<TValue>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return (NamedValue<TValue>)yesNamedValue; // ERROR: cannot convert type
yield return (NamedValue<TValue>)noNamedValue; // ERROR: cannot convert type
}
}
Why does NamedValueSource<TValue> compile while NamedValueSourceFail<TValue> errors out? Specifically, why am I able to perform the cast using Linq but not with good ol' parantheses?
Edit
In case it's not entirely clear from the comment thread of the accepted answer, I simply needed to convert to object first, then I would be allowed to cast to NamedValue<TValue>. This is probably how the Linq Cast method works behind the scenes.
UPDATE: This question was the subject of my blog on July 10th 2012; thanks for the great question!
Let's greatly simplify your complicated program.
public static class X
{
public static V Cast<V>(object o) { return (V)o; }
}
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = X.Cast<C<U>>(new C<bool>());
}
}
Now your second version, simplified:
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(new C<bool>());
}
}
OK, so now let's ask some questions.
Why does the second program fail at compile time?
Because there is no conversion from C<bool> to C<U> for arbitrary U. The compiler knows that the only way this could possibly succeed is is U is always bool, and therefore this program is almost certainly wrong! The compiler assumes that U is going to be something other than bool some of the time.
Why then does the first program succeed at compile time?
The compiler has no idea that a method named "X.Cast" should be treated like a cast operator for the purposes of error detection! As far as the compiler is concerned, the Cast method is a method that takes an object in and returns a V for whatever type parameter is provided for V. When compiling the body of the ctor of D, the compiler has no idea whatsoever that some method, which probably isn't even in this program to begin with, is going to try to do a cast that is going to fail unless U happens to be bool.
The compiler simply has no basis upon which to treat the first version as an error, even though it most certainly is a deeply wrong program. You'll have to wait until runtime to find out that your program is wrong.
Now let's make a third version of your program:
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(object)(new C<bool>());
}
}
This succeeds at compile time, so let's ask:
Why does this succeed at compile time?
For the exact same reason that the first one succeeds at compile time. When you inserted the cast you effectively said that you wanted the newly constructed C<bool> to be treated as an object, and so for the rest of the analysis of this expression, that expression is considered to be of type object, and not the more specific type C<bool>.
So then why is it legal to cast object to C<U> in this case? Or for that matter, to V in the first case?
It is legal to cast object to V because V could be the type of the object, a base type of the object or an interface implemented by the object, so the compiler allows the conversion because it figures there are a lot of ways it could possibly succeed.
Basically, it is legal to cast object to anything that you could convert to object. You cannot cast object to a pointer type, for instance, because no pointer type can be cast to object. But everything else is fair game.
By making the cast to object first, you are removing information from the purview of the compiler; you are saying "ignore the fact that you know this is always C<bool> for the purposes of error detection.
In your second example, you're trying to convert NamedValue<bool> to NamedValue<TValue> -- this won't work, because the conversion has to be valid for any type argument. You can't convert NamedValue<bool> to NamedValue<int> or NamedValue<string> or NamedValue<AnythingElseOtherThanBool>.
One solution is to make NamedValueSource<TValue> abstract, as well as its GetNamedValues() method, and then create a class BooleanNamedValueSource : NamedValueSource<bool> class to use in your test.
In the linq case, the cast is not being done by the compiler; the cast occurs in a method that has already been compiled. All the compiler knows is that it is calling a method that takes IEnumerable<bool> and returns IEnumerable<TValue>. The specifics of that conversion are entirely invisible to the compiler.
I have a custom implementation of the string class. I added custom conversion operators between string and the class, and the casting is working normally. But, if I first cast the custom object to System.Object and then to string it says: "Unable to cast the type 'MyString' to type 'System.String'". Why is that? How can I enable it...
class MyString
{
public string S {get; set;}
public MyString(string s)
{
this.S = s;
}
public static implicit operator string(MyString s)
{
return s.S;
}
public static implicit operator MyString(string s)
{
return new MyString(s);
}
}
class Program
{
static void Main(string[] args)
{
MyString ms = new MyString("a");
string s = ms;
object o = ms;
string s1 = (string)o; // <-- this throws the exception!
}
}
Conversions like this have to be determined at compile-time - whereas in your final line, the compile-time type of o is just object, so the compiler doesn't "know" about your conversion as an option.
It's hard to know the best solution to your problem other than just saying "don't do that" - if you use dynamic instead of object (and you're using C# 4, of course) then it'll work - but personally I would just try not to rely on user-defined conversions like this. They make the codebase very hard to understand, IMO.
Anyone reading an expression (string) o where o is just object would expect it to be a simple cast, i.e. one which would fail if o didn't actually refer to a string (or was a null reference). Trying to find ways of confounding that expectation is a bad idea, IMO.
I'd override ToString in your class. And then use o.ToString() instead of (string)o.