簡體   English   中英

如何在反射中使用索引屬性的SetValue?

[英]How to use SetValue of an Indexed Property in Reflection?

我有一個C#轉換器方法,該方法可以使用反射來轉換通用列表。

當我嘗試調用Item屬性的SetValue方法時,會發生此問題,它引發以下內部異常(ArgumentOutOfRangeException):

索引超出范圍。 必須為非負數並且小於集合的大小。 參數名稱:索引。

這是我的代碼:

internal class Program
{
    private static void Main()
    {
        List<ClassA> classA = new List<ClassA>();
        classA.Add(new ClassA { Data = "value1" });
        classA.Add(new ClassA { Data = "value2" });

        List<ClassB> classB = Converter<List<ClassA>, List<ClassB>>(classA);
    }

    public static TOut Converter<TIn, TOut>(TIn request)
    {
        var response = Activator.CreateInstance<TOut>();
        PropertyInfo propertyA = typeof(TIn).GetProperty("Item");
        PropertyInfo propertyB = typeof(TOut).GetProperty("Item");

        int count = (int)typeof(TIn).GetProperty("Count").GetValue(request);
        for (int i = 0; i < count; i++)
        {
            var value = propertyA.GetValue(request, new object[] { i });
            var b = CreateBFromA(propertyB, propertyA, value);
            propertyB.SetValue(response, b, new object[] { i });
        }

        return response;
    }

    private static object CreateBFromA(PropertyInfo propertyB, PropertyInfo propertyA, object value)
    {
        var b = Activator.CreateInstance(propertyB.PropertyType);
        object o = propertyA.PropertyType.GetProperty("Data").GetValue(value);
        propertyB.PropertyType.GetProperty("Data").SetValue(b, o);
        return b;
    }
}

internal class ClassA
{
    public string Data { get; set; }
}

internal class ClassB
{
    public string Data { get; set; }

    public object Other { get; set; }
}

這是一個更大的通用方法的小示例代碼(我需要在其中使用反射),因此您可以嘗試運行它以重新生成異常。

如何使用SetValue方法來避免此異常?

這是我的建議:

public static TCollectionOut ConvertCollection<TCollectionIn, TCollectionOut, TIn, TOut>(TCollectionIn input)
        where TCollectionIn : IEnumerable<TIn>
        where TCollectionOut : ICollection<TOut>, new()
        where TOut : new()
    {
        var res = new TCollectionOut();

        foreach (dynamic item in input)
        {
            dynamic o = new TOut();
            ConvertItem(item, o);
            res.Add(o);
        }
        return res;
    }

    public static TCollectionOut ConvertCollectionMoreDynamic<TCollectionIn, TCollectionOut>(TCollectionIn input)
        where TCollectionIn : IEnumerable

    {
        dynamic res = Activator.CreateInstance(typeof (TCollectionOut));

        var oType = typeof (TCollectionOut).GetMethod("Add").GetParameters().Last().ParameterType;

        foreach (dynamic item in input)
        {
            dynamic o = Activator.CreateInstance(oType);
            ConvertItem(item, o);
            res.Add(o);
        }
        return res;
    }

    public static void ConvertItem(ClassA input, ClassB output)
    {
        output.Data = input.Data;
    }

如果您希望支持更多類型,則只需創建具有正確重載的ConvertItem方法即可。

這是因為您試圖將索引傳遞給未索引的屬性(數據)。

如果您發布ClassA代碼,我可以嘗試提供幫助。 無論如何,您都可以使用LINQ來執行這種轉換。 它更快(編寫和執行)和鍵入安全。

暫無
暫無

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

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