如何从反射执行显式操作转换?

Dav*_*rab 11 c# operators implicit-conversion explicit-conversion

我想使用反射,并使用反射进行隐式或显式转换.

鉴于我已经用这种方式定义了Foo

public class Foo
{
    public static explicit operator decimal(Foo foo)
    {
        return foo.Value;
    }

    public static explicit operator Foo(decimal number)
    {
        return new Foo(number);
    }

    public Foo() { }

    public Foo(decimal number)
    {
        Value = number;
    }

    public decimal Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时

decimal someNumber = 42.42m;

var test = (Foo)someNumber;

Console.WriteLine(test);        // Writes 42.42 No problems
Run Code Online (Sandbox Code Playgroud)

当我尝试使用Foo定义一个类作为成员类型并使用反射来设置它时.我得到以下例外.

Error     : Object of type 'System.Decimal' cannot be converted to type 'Foo'.
StackTrace:    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.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
               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)
Run Code Online (Sandbox Code Playgroud)

这是我用于使用反射设置属性的代码

public class FooComposite
{
    public Foo Bar { get; set; }
}

var properties = typeof(FooComposite).GetProperties();

var testFoo = new FooComposite();

foreach(var propertyInfo in properties)
{
    propertyInfo.SetValue(testFoo, 17.17m, null);  // Exception generated on this line
}

Console.WriteLine(testFoo.Bar);  // Never gets here
Run Code Online (Sandbox Code Playgroud)

我该怎么做这个转换?

Jam*_*iec 5

那么它与你的非反射代码没有什么不同,你仍然需要明确地将数字转换为Foo:

propertyInfo.SetValue(testFoo,(Foo)17.17m, null);
Run Code Online (Sandbox Code Playgroud)

实例:http://rextester.com/rundotnet?code = BPQ74480

出于兴趣,我尝试了一些替代方案.

  1. 使它成为一个implicit演员Foo- 没有工作,同样的错误直播
  2. 使用Convert.ChangeType(17.17m,typeof(Foo))- 也不起作用.生活


Her*_*man 5

我需要像 Ted H 这​​样的功能,但我是这样实现的:

var cast = typeof(dest).GetMethod("op_Explicit", new Type[] { typeof(source) });
var result = cast.Invoke(null, new object[] {value});
Run Code Online (Sandbox Code Playgroud)

编辑:我最近需要一个更进化的版本,这就是我想出的。请注意,它并未涵盖所有可用的转换。

private static object DynamicCast(object source, Type destType) {
    Type srcType = source.GetType();
    if (srcType == destType) return source;

    var paramTypes = new Type[] { srcType };
    MethodInfo cast = destType.GetMethod("op_Implicit", paramTypes);

    if (cast == null) {
        cast = destType.GetMethod("op_Explicit", paramTypes);
    }

    if (cast != null) return cast.Invoke(null, new object[] { source });

    if (destType.IsEnum) return Enum.ToObject(destType, source);

    throw new InvalidCastException();

}
Run Code Online (Sandbox Code Playgroud)