简体   繁体   中英

How to use SetValue of an Indexed Property in Reflection?

I have a C# Converter method which convers generic lists with the use of reflection.

The problem occurs when I try to call the SetValue method of the Item's property, it throws the following inner exception (ArgumentOutOfRangeException):

Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index.

Here is my code:

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

This is a small example code of a bigger generic method (where I need to use reflection), so you can try and run it to regenerate the exception.

How to use the SetValue method to avoid this exception?

Here is my aproach to it:

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

If you wich to support more types just create ConvertItem method with correct overload.

This is because you are trying to pass an index to a not indexed property (Data).

If you post the ClassA code I can try yo help. Anyway you can use LINQ to perform this kind of conversions. It's faster (to write and to execute) and type safe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM