Raw*_*ing 7 c# reflection type-conversion
我继承了一些试图设置属性的代码:
object target = ... // some instance on which we want to set a property
object value = ... // some value - in this case, a string
var propertyInfo = ... // some property of target - in this case, not a string
try
{
propertyInfo.SetValue(obj, value, null);
}
catch (ArgumentException)
{
// We go off and look for our own way of converting between
// the type of value and the type of the property.
}
Run Code Online (Sandbox Code Playgroud)
在当前使用中,异常被捕获并抛出很多,所以我想首先进行检查:
if (propertyInfo.PropertyType.IsAssignableFrom(value.GetType())
{
// Try/catch as above
}
else
{
// Do the manual conversion as if the exception had been thrown.
}
Run Code Online (Sandbox Code Playgroud)
这运行得更快.但是,我唯一担心的是,对于某些实际上会成功的类型,IsAssignableFrom可能会返回.(这会导致我们在不需要时查找手动转换,并且可能无法完全设置值.)falseSetValue
规格SetValue说
value无法转换为PropertyType的类型
这与可分配性不完全相同.
(如果在失败的情况下IsAssignableFrom返回,那很好 - 手动转换仍然会发生.)trueSetValue
有人可以向我确认这是否可行?
正如您所怀疑的,尽管returns ,但可以通过反射将type 的值short分配给 type 的属性。inttypeof(int).IsAssignableFrom(typeof(short))false
查看堆栈跟踪ArgumentException:
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
at System.Reflection.PropertyInfo.SetValue(Object obj, Object value)
at ConsoleApplication3.Program.Main(String[] args) in ...
Run Code Online (Sandbox Code Playgroud)
异常被抛出RuntimeType.TryChangeType。查看mscorlib中的源码:
// System.RuntimeType
[SecurityCritical]
private object TryChangeType(object value, Binder binder, CultureInfo culture, bool needsSpecialCast)
{
...
if (this.IsInstanceOfType(value))
{
return value;
}
...
if (RuntimeType.CanValueSpecialCast(valueType, this))
{
...
}
throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,有许多内部函数被调用来确定是否ArgumentException应该抛出 an 。我怀疑基元的转换是在该函数周围处理的:
// System.RuntimeType
[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool CanValueSpecialCast(RuntimeType valueType, RuntimeType targetType);
Run Code Online (Sandbox Code Playgroud)
还有一些有趣的代码System.RuntimeType.CheckValue(object, Binder, CultureInfo, BindingFlags):
bool flag = base.IsPointer || this.IsEnum || base.IsPrimitive;
if (flag)
{
...
if (RuntimeType.CanValueSpecialCast(valueType, this))
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
所以看起来指针、枚举和原始类型的处理方式不同。我不鼓励你尝试复制这个逻辑。IsAssignableFrom仅使用, 并单独处理整数类型可能会更容易。处理指针、枚举和原始类型参数看起来非常复杂,我会回退到try-catch那里。但是,如果发生参数错误,您可以缓存,因此对具有相同参数类型的同一方法的后续调用可能会更快一些。
| 归档时间: |
|
| 查看次数: |
758 次 |
| 最近记录: |