Dynamic Property Assignment Throws RuntimeBinderException - c#

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

Related

C# variable type name [duplicate]

I'm looking for how to get compile time type of a variable for debugging purposes.
The testing environment can be reproduced as simply as:
object x = "this is actually a string";
Console.WriteLine(x.GetType());
Which will output System.String. How could I get the compile time type System.Object here?
I took a look over at System.Reflection, but got lost in the amount of possibilities it provides.
I don't know if there is a built in way to do it but the following generic method would do the trick:
void Main()
{
object x = "this is actually a string";
Console.WriteLine(GetCompileTimeType(x));
}
public Type GetCompileTimeType<T>(T inputObject)
{
return typeof(T);
}
This method will return the type System.Object since generic types are all worked out at compile time.
Just to add I'm assuming that you are aware that typeof(object) would give you the compile time type of object if you needed it to just be hardcoded at compile time. typeof will not allow you to pass in a variable to get its type though.
This method can also be implemented as an extension method in order to be used similarly to the object.GetType method:
public static class MiscExtensions
{
public static Type GetCompileTimeType<T>(this T dummy)
{ return typeof(T); }
}
void Main()
{
object x = "this is actually a string";
Console.WriteLine(x.GetType()); //System.String
Console.WriteLine(x.GetCompileTimeType()); //System.Object
}

Why does the C# compiler allow a cast to be performed with Linq but not with parentheses?

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.

C# Casting with conversion operators

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.

explicit cast operator applied to instance created through reflection

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.

Nullable type as a generic parameter

I'm trying to implement a class that stores a generic nullable type:
public class myclass<T?>
{
T? myvariable;
public T? myfunction(){
return myvariable;
}
}
And while the above class compiles just fine, the actual use that provides trouble:
myclass<int?> c = new myclass<int>();
int? = c.myfunction(); // does not work: implicit cast from type T? in int? not possible.
// or, assuming the variable is not null
int = c.myfunction().Value; // implicit cast from type T in int not possible.
What am I doing wrong or how can I work around this?
Neither of the examples compile:
<T?> isn't valid syntax; it should be <T>
myclass needs a where T : struct constraint
The first line of your second example should read: myclass<int> c = new myclass<int>();.
The rest of your second example should compile OK, however.

Categories