簡體   English   中英

如何通過反射設置作為通用接口的字段的值?

[英]How do I set value of field that is a generic interface through reflection?

我希望能夠使用反射來獲得IList類型的類的成員,並且我想為其創建一個委托,以便為反射花更少的錢。 所有這些使我可以通過傳入實例和新的List來調用委托。 每當我嘗試這樣做時,C#都會給我無效的強制轉換異常。 我在泛型中缺少一些愚蠢的東西嗎?

我嘗試過使用沒有泛型的接口字段,並且這些字段似乎工作正常。 我似乎只在使用泛型時遇到問題。 我還嘗試使用Convert.ChangeType將我的輸入轉換為所需的類型,並且出現有關List <>的錯誤,該錯誤未實現IConvertible。 如果我可以使用反射從具體的List <>設置IList <>類型的值,我會很高興的:)

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

public class MyObject
{
    public IList<int> MyField;
}

public class ReflectionPerfTesting
{

    public void Run()
    {
        var testObject = new MyObject();
        var field = testObject.GetType().GetField("MyField", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        InvokeUsingReflection(field, testObject);
    }

    private void InvokeUsingReflection(FieldInfo fieldInfo, object testObject)
    {
        var fieldType = fieldInfo.FieldType;
        var sourceType = fieldInfo.DeclaringType;

        // ZAS: create value parameter
        var valueParam = Expression.Parameter(fieldType);

        // ZAS: create targetParameter
        var sourceParam = Expression.Parameter(sourceType);

        var field = Expression.Field(sourceParam, fieldInfo);
        var returnExpression = (Expression)Expression.Assign(field, valueParam);
        if (!fieldType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, fieldType);
        }

        // ZAS: create generic delegate from definition
        var delegateType = typeof(Action<,>);
        var genericType = delegateType.MakeGenericType(sourceType, fieldType);

        // ZAS: Create lambda for faster access to setter using reflection. This is meant to be cached!
        var lambdaExpression = Expression.Lambda(genericType, returnExpression, sourceParam, valueParam);
        var lambda = lambdaExpression.Compile();
        var lambdaInvokeMethod = lambda.GetType().GetMethod("Invoke");

        var list = new List<int>();
        lambdaInvokeMethod.Invoke(testObject, new object[] { list });
    }

}

對我來說,預期的結果是能夠將“ setter”緩存到該屬性,並支持設置任何類型的值,包括泛型和接口。 我當前的結果是,在有泛型的情況下,任何類型的設置值都可以工作,所以我必須做錯了什么。

您的lambda通話有誤。 您必須在傳遞目標以及參數的lambda對象上Invoke方法。

如果解決此問題,則可獲得所需結果:

testObject.Dump();

var list = new List<int>();
lambdaInvokeMethod.Invoke(lambda, new object[] { testObject, list });

testObject.Dump();

Dumping object(MyObject)
 MyField  : null
Dumping object(MyObject)
 MyField  : []

參見: https : //dotnetfiddle.net/FZN3iX

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM