I'm having this issue, I'm using reflection to pull properties from a class but the problem is reflection returns them as an object and I can't get it into my actual type.
Take for example, if this is the class:
public class Row<T>
{
public static explicit operator Row<object>(Row<T> o)
{
return new Row<object>
{
Name = o.Name,
Value = o.Value
};
}
public string Name { get; set; }
public T Value { get; set; }
}
Casting from one say Row<bool>
to Row<object>
works:
var a = new Row<bool>
{
Name = "Foo",
Value = true
};
var b = (Row<object>)a; // Works
But when I try to go from object
to Row<object>
it seems to ignore my explicit operator and throw a System.InvalidCastException:
var c = (object) a; // Simulate getting from reflection
var d = (Row<object>) c; // System.InvalidCastException
What am I missing?
Use dynamic
instead of object
to force runtime real type check:
var c = (dynamic)a;
var d = (Row<object>)c; // Works fine
It will call your Row<T> -> Row<object>
cast operator.
The problem here is that casting does not look for a conversion operator unless one is defined on the static type of the value you are trying to cast. In your example the static type of c
is object
and object
neither derives from nor has a conversion operator to Row<object>
, resulting in the runtime exception.
It looks like this problem can be easily sidestepped with a better design.
You want to treat any type of Row<T>
as a Row<object>
and the conversion operator does nothing more than work around the fact that these types are not hierarchically related. So why not make them related and avoid the problem in the first place?
For example:
public abstract class Row
{
public string Name { get; set; }
public object Value { get; protected set; }
}
public class Row<T> : Row
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
This seems to do what you want:
Row<T>
to the base class Row
(which takes over the responsibilities of Row<object>
in your initial design) and easily access Name
and Value
no matter what type the Value
is.Row.Value
setter is protected so you cannot cast a Row<int>
to Row
and make Value
e.g. a string
from outside, maintaining type safety.You can accomplish this with reflection:
public class RowHelper
{
public static Row<object> LoadRow(object o)
{
var type = o.GetType();
return new Row<object>
{
Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null),
Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null)
};
}
}
You would call this with:
var d = RowHelper.LoadRow(c);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With