15

リフレクションを使用し、リフレクションを使用して暗黙的または明示的なカバーを実行したいと考えています。

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();
    }
}

このコードを実行すると

decimal someNumber = 42.42m;

var test = (Foo)someNumber;

Console.WriteLine(test);        // Writes 42.42 No problems

メンバー型として 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)

リフレクションでプロパティを設定するために使用するコードは次のとおりです

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

この変換を行うにはどうすればよいですか?

4

5 に答える 5

6

それはあなたの非リフレクションコードと本当に違いはありませんが、数値を明示的にキャストする必要がありますFoo:

propertyInfo.SetValue(testFoo,(Foo)17.17m, null);

実際の例: http://rextester.com/rundotnet?code=BPQ74480

興味があったので、いくつかの代替案を試しました。

  1. キャストimplicitにしFooます-機能しません、同じエラーLive
  2. 使用Convert.ChangeType(17.17m,typeof(Foo))- また動作しません。ライブ
于 2011-09-08T16:24:12.090 に答える
6

Ted H のような機能が必要でしたが、次のように実装しました。

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

編集:最近、より進化したバージョンが必要でした。これが私が思いついたものです。利用可能なすべての変換を網羅しているわけではないことに注意してください。

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();

}
于 2013-07-17T16:59:29.550 に答える
4

反省すれば何でもできる。

私の問題は、複雑な型のために 2 つのクラス間でディープ コピーを作成しようとするリフレクション メソッドでした。変換を定義しようとしexplicit operatorましたが、呼び出されないようだったので、リフレクションで取得する方法を見つけました。静的メソッドの呼び出しに関する他の調査を使用して、pSource に格納されている複合型をプロパティ pDest の別の型にコピーするときに、これが機能することがわかりました。pDest の型には、pSource の型からの変換があります。


MethodInfo[] static_methods = pDest.PropertyType.GetMethods(System.Reflection.BindingFlags.Static | BindingFlags.Public);
if (static_methods != null)
{
    foreach (MethodInfo method in static_methods)
    {
        if(method.Name== "op_Explicit")                       // this is a constant
        {                                                     // for explicit operators
            ParameterInfo[] paramSet = method.GetParameters();
            if ((paramSet != null) && (paramSet.Length == 1)) 
            {
                if (paramSet[0].ParameterType == pSource.PropertyType) // match the types!
                {
                    pDest.SetValue(                          // Destination prop
                        dstVar,                              // Destination instance
                        method.Invoke(                       // converter method
                              null,                          // static has no 'this'
                              new object[] {                 // value to convert from
                                  pSource.GetValue(source, null) 
                              }                              // source property on
                                                             // source instance
                        )
                    ); // SetValue(...)
                }
            }
        }
    }
}

dstVar は宛先インスタンスです。pDest は、宛先インスタンスの現在の PropertyInfo です。

source は私のソース インスタンスです。pSource は、ソース インスタンスの現在の PropertyInfo です。

宛先プロパティに使用される型には、ソース プロパティの型からの明示的な変換があります。これは、何も必要とせずに機能します。

于 2012-09-06T22:44:33.680 に答える