C# Type Casting at Runtime for Array.SetValue
I'm trying to create an array using reflection, and insert values into it. I'm trying to do this for many different types so would like a createAndFillArray
function capable of this :
String propertyName1 = "prop1";
String propertyName2 = "prop2";
Type t1 = typeof(myType).getProperty(propertyName1).PropertyType.getElementType();
Type t2 = typeof(myType).getProperty(propertyName2).PropertyType.getElementType();
double exampleA = 22.5;
int exampleB = 43;
Array arrA = createAndFillArray(t1, exampleA);
Array arrB = createAndFillArray(t2, exampleB);
private Array createAndFillArray(Type t, object val){
Array arr = Array.CreateInstance( t, 1); //length 1 in this example only, real-worl开发者_如何学JAVAd is of variable length.
arr.SetValue( val, 0 ); //this causes the following error: "System.InvalidCastException : Object cannot be stored in an array of this type."
return arr;
}
with the class A being as follows:
public class A{
public A(){}
private double val;
public double Value{
get{ return val; }
set{ this.val = value; }
}
public static implicit operator A(double d){
A a = new A();
a.Value = d;
return a;
}
}
and class B being very similar, but with int
:
public class B{
public B(){}
private double val;
public double Value{
get{ return val; }
set{ this.val = value; }
}
public static implicit operator B(double d){
B b = new B();
b.Value = d;
return b;
}
}
and myType is something like the following:
public class myType{
public A prop1{ get; set; }
public B prop2{ get; set; }
}
I hoped that the implicit operator would have ensured that the double be converted to class A, or the int to class B, and the error avoided; but this is obviously not so.
The above is used in a custom deserialization class, which takes data from a custom data format and fills in the corresponding .Net object properties. I'm doing this via reflection and at runtime, so I think both are unavoidable. I'm targeting the C# 2.0 framework.
I've dozens, if not hundreds, of classes similar to A
and B
, so would prefer to find a solution which improved on the createAndFillArray
method rather than a solution which altered these classes.
Here's an example of using reflection to find the conversion method. So if you can get that method on your type and do the conversion your self.
Copied from: http://bytes.com/topic/c-sharp/answers/903775-getting-operators-using-reflection
//EndType is the type I want to PRODUCE
//StartType is the type I am pulling data FROM
MethodInfo mi = EndType.GetMethod(
"op_Implicit",
(BindingFlags.Public | BindingFlags.Static),
null,
new Type[] { StartType },
new ParameterModifier[0]
);
//Now if mi is NOT null, it means there is an operator that allows for converting StartType to EndType, if it is null, there isn't one
Casting is resolved at compile time, which in your case would be looking at at the type of the first parameter to Array.SetValue
which is of type object
, the 0 will be cast to type object
(ie. boxed).
Is there a reason that you need to use reflection? As others have posted you can do this with generics.
Here is an approximation of your reflection code using generics
private T[] createAndFillArray<T>(T val)
{
T[] array = new T[1];
array[0] = val;
return array;
}
Which you can call as follows
Array arrA = createAndFillArray<A>(exampleA);
Array arrB = createAndFillArray<B>(exampleB);
Based on your comment one possible implementation might be
private Array createAndFillArray(Type t, string property, object val)
{
object element = Activator.CreateInstance(t);
PropertyInfo pi = t.GetProperty(property);
if (pi != null)
{
pi.SetValue(element, val, null);
}
Array arr = Array.CreateInstance(t, 1);
arr.SetValue(element, 0);
return arr;
}
Which you can use as follows
Array arrB = createAndFillArray(t2, "Value", exampleB);
Where "Value" is the name of the property in the target type that you want to set.
First, generics would make the array creation trivial:
public static T[] CreateAndFill<T>(params T[] values)
{
var retval = new T[values.Length];
for (int i = 0; i < values.Length; i++)
retval[i] = values[i];
return retval;
}
Second, one reason why your implicit casts aren't working could be because the method you're using to set the value in the array actually ends in an extern
call (into what library I can't tell via Reflector), which most likely doesn't check for the implicit conversion.
Would this work...
private Array createAndFillArray<T>(object val){
Array arr = Array.CreateInstance(typeof(t), 1); //length 1 in this example only, real-world is of variable length.
arr.SetValue( (T)val, 0 ); //this causes the following error: "System.InvalidCastException : Object cannot be stored in an array of this type."
return arr;
}
精彩评论