将List <double []>转换为List <t> </t> </double []>

时间:2013-05-13 16:25:33

标签: c# .net reflection

我有一个双打List<double[]>列表,我想将其转换为List<T>,其中T是一个类。

double数组包含17个值,例如[1.0,2.0,3.0,4.0,5.0,.. 17.0]。 然后我有一个类定义了17个字符串属性,例如P1,P2,....,P17

因此List<double[]>的每个元素都是一个双精度数组,数组中的每个元素都代表T类中属性的值。

是否可以将给定双打数组的每个索引映射到类型为T的类的属性。所以我将List<double[]>转换为List<T>T为{{1} }}

我知道可以通过手动迭代读取每个数组的列表来完成 从数组的每个索引读取值并将其传递给类的相应属性。 但是当我有10多个属性的课程时,要做很多事情。

编辑:其中一个类的示例如下所示

class

EDIT2 :从列表中创建列表的方法,注意 _profiler.FinalCentroid的类型为 /// <summary> /// Defines the properties of a centroid. /// </summary> public class Centroid { // ReSharper disable InconsistentNaming /// <summary> /// Calls made to contacts /// </summary> public string CONTACT_CALLS { get; set; } /// <summary> /// Duration of calls made to contacts /// </summary> public string CONTACT_CALLS_SEC { get; set; } /// <summary> /// Calls made to non contacts /// </summary> public string UNKNOWN_CALLS { get; set; } /// <summary> /// Duration of calls made to non contacts /// </summary> public string UNKNOWN_CALLS_SEC { get; set; } /// <summary> /// Number of SMS sent to contacts /// </summary> public string SMS_OUT_CONTACTS { get; set; } /// <summary> /// Number of SMS sent to non contacts /// </summary> public string SMS_OUT_UNKNOWN { get; set; } /// <summary> /// Percentage of CPU usaed /// </summary> public string CPU_USAGE { get; set; } /// <summary> /// Percentage of RAM used /// </summary> public string RAM_USAGE { get; set; } /// <summary> /// Number of system application /// </summary> public string SYS_APPS { get; set; } /// <summary> /// Number of user applications /// </summary> public string USER_APPS { get; set; } /// <summary> /// Number of system services /// </summary> public string SYS_SERVICES { get; set; } /// <summary> /// Number of user services /// </summary> public string USER_SERVICES { get; set; } /// <summary> /// Number of bytes sent /// </summary> public string BYTES_TX { get; set; } /// <summary> /// Number of bytes received /// </summary> public string BYTES_RX { get; set; } /// <summary> /// Latitute of the location /// </summary> public string LOC_LAT { get; set; } /// <summary> /// Longitude of the location /// </summary> public string LOC_LON { get; set; } /// <summary> /// The Time Slice /// </summary> public string TIME_SLICE { get; set; } // ReSharper restore InconsistentNaming }

List<double[]>

4 个答案:

答案 0 :(得分:5)

要发布明显的,为什么不在构造函数中分配属性?
您将开始创建属性的工作 在构造函数中分配值的键击次数少于属性。

List<double[]> ld = new List<double[]>();
List<PropDouble> lpd = new List<PropDouble>();
foreach (double[] da in ld) { lpd.Add(new PropDouble(da)); }

public class PropDouble
{
    public double P0 { get; set; }
    public double P1 { get; set; }
    public PropDouble(double[] doubles) { P0 = doubles[0]; P1 = doubles[1]; }
}

public class PropDouble
{
    private double[] doubles;
    public double P0 { get { return doubles[0]; } set { doubles[0] = value; } }
    public double P1 { get { return doubles[1]; } set { doubles[1] = value; } }
    public PropDouble(double[] Doubles) { doubles = Doubles; }
}

答案 1 :(得分:2)

编辑:正如Blam所指出的那样,最明显的答案是一个简单的构造函数,我会更新这个答案以获得更复杂的场景。

假设您从不同位置获取阵列。它们可能有不同的顺序或可能缺少值。在这种情况下,您可以使用custom attributesreflection将属性映射到不同的数组索引。每个映射都被命名,以便您可以为不同的数组使用不同的索引(或根本不使用)。

请注意,反射会大大降低性能。对于少数几个对象,这个成本几乎不值得注意,但是如果你要处理数千个或更多的对象,那么你可能需要考虑重构。

这是您用于将属性映射到索引的自定义属性

[AttributeUsage( AttributeTargets.Property, AllowMultiple = true )]
class ArrayToPropertyMap : Attribute
{
    public string ArrayName
    {
        get;
        set;
    }

    public int ArrayIndex
    {
        get;
        set;
    }

    /* Call this function to do the actuall mapping (target is updated) */
    public static IEnumerable<U> Map<U, T>( IEnumerable<T[]> source, string arrayName ) where U : new()
    {
        if ( !source.Any() )
            return new U[] { };

        var l_mappedProperties =
            typeof( U )
            .GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance )
            .Where(
                p => ( p.PropertyType == typeof( T ) ) && Attribute.IsDefined( p, typeof( ArrayToPropertyMap ) ) )
            .Select(
                p => new
                {
                    Property = p,
                    Attribute = p.GetCustomAttributes( typeof( ArrayToPropertyMap ), true )
                                 .Cast<ArrayToPropertyMap>()
                                 .Where( a => a.ArrayName == arrayName )
                                 .FirstOrDefault()
                } )
            .Where(
                p => p.Attribute != null )
            .Select(
                p => new
                {
                    Property = p.Property,
                    Index = p.Attribute.ArrayIndex
                } );

        var l_result = new List<U>();

        foreach ( var array in source )
        {
            var l_target = new U();
            foreach ( var l_mappedProperty in l_mappedProperties )
                l_mappedProperty.Property.SetValue( l_target, array[l_mappedProperty.Index], null );
            l_result.Add( l_target );
        }

        return l_result;
    }

}

这是一个示例类(因此您可以看到它正常工作)

class LotsaProps1
{

    [ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 0 )]
    [ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 3 )]
    public string Prop1
    {
        get;
        set;
    }

    [ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 2 )]
    [ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 2 )]
    public string Prop2
    {
        get;
        set;
    }

    /* Notice that Prop3 is not mapped to Array1 */
    [ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 1 )]
    public string Prop3
    {
        get;
        set;
    }

    [ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 1 )]
    [ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 0 )]
    public string Prop4
    {
        get;
        set;
    }
}

这部分只是运行示例

class Program
{
    static void Main( string[] args )
    {

        /* You should already have the arrays... */
        string[][] arr1 = new string[][] { 
            new string[] { "Value A 1", "Value A 2", "Value A 3" },
            new string[] { "Value A 4", "Value A 5", "Value A 6" },
            new string[] { "Value A 7", "Value A 8", "Value A 9" },
        };
        string[][] arr2 = new string[][] { 
            new string[] { "Value B 1", "Value B 2", "Value B 3", "Value B 4" },
            new string[] { "Value B 5", "Value B 6", "Value B 7", "Value B 8" },
            new string[] { "Value B 9", "Value B 10", "Value B 11", "Value B 12" },
        };

        /* ...so this is really the only code you'd need to add to your
              business logic: */
        var l_objs1 = ArrayToPropertyMap.Map<LotsaProps1, string>( arr1, "Array1" );
        var l_objs2 = ArrayToPropertyMap.Map<LotsaProps1, string>( arr2, "Array2" );

        /* This code is just used to show that the example works: */
        Console.WriteLine( "Array1:" );
        foreach ( var l_obj in l_objs1 )
        {
            Console.Write( "Prop1='" + l_obj.Prop1 + "'; " );
            Console.Write( "Prop2='" + l_obj.Prop2 + "'; " );
            Console.Write( "Prop3='" + l_obj.Prop3 + "'; " );
            Console.WriteLine( "Prop4 = '" + l_obj.Prop4 + "'" );
        }
        Console.WriteLine( "Array2:" );
        foreach ( var l_obj in l_objs2 )
        {
            Console.Write( "Prop1='" + l_obj.Prop1 + "'; " );
            Console.Write( "Prop2='" + l_obj.Prop2 + "'; " );
            Console.Write( "Prop3='" + l_obj.Prop3 + "'; " );
            Console.WriteLine( "Prop4 = '" + l_obj.Prop4 + "'" );
        }

        Console.ReadKey( true );

    }
}

<强>输出

Array1:
Prop1='Value A 1'; Prop2='Value A 3'; Prop3=''; Prop4 = 'Value A 2'
Prop1='Value A 4'; Prop2='Value A 6'; Prop3=''; Prop4 = 'Value A 5'
Prop1='Value A 7'; Prop2='Value A 9'; Prop3=''; Prop4 = 'Value A 8'
Array2:
Prop1='Value B 4'; Prop2='Value B 3'; Prop3='Value B 2'; Prop4 = 'Value B 1'
Prop1='Value B 8'; Prop2='Value B 7'; Prop3='Value B 6'; Prop4 = 'Value B 5'
Prop1='Value B 12'; Prop2='Value B 11'; Prop3='Value B 10'; Prop4 = 'Value B 9'

答案 2 :(得分:0)

using System;

class Test
{
    public string P1 { get; set; }

    public string P2 { get; set; }
}

class MainClass
{
    static T MapArray<T>(double[] array, string propertyStartWith) where T: new()
    {
        T obj = new T();
        Type t = typeof(T);
        for (int i = 0; i < array.Length; i++)
        {
            var property = t.GetProperty(propertyStartWith + (i + 1).ToString());
            property.SetValue(obj, Convert.ChangeType(array[i], property.PropertyType), null);
        }
        return obj;
    }

    public static void Main (string[] args)
    {
        double[] d = new double[] {
            Math.PI, Math.E
        };
        Test t = MapArray<Test> (d, "P");
        Console.WriteLine (t.P1);
        Console.WriteLine (t.P2);
    }
}

答案 3 :(得分:0)

这是一个没有错误检查的简单实现,但您可以指定自己的转换函数。目前它默认为Convert.ChangeType:

void Main()
{
    var list = new List<double> { 1.0, 1.1, 2.2, 3.3 };
    var instances = new List<A> { new A(), new A(), new A(), new A() };
    ConvertZipMap(list, instances, item => item.P);

    // 1
    // 1
    // 2
    // 3
}

class A {
    public int P { get; set; }
}

void ConvertZipMap<TSource,TTarget,TProperty>(
    IEnumerable<TSource> source,
    IEnumerable<TTarget> target,
    Expression<Func<TTarget, TProperty>> propertySelector,
    Func<TSource, TProperty> conversion = null) {

    // create setter
    var member = (MemberExpression)propertySelector.Body;
    var param = Expression.Parameter(typeof(TProperty), "value");
    var setExpr = Expression.Lambda<Action<TTarget, TProperty>>(
        Expression.Assign(member, param),
        propertySelector.Parameters[0],
        param);
    var set = setExpr.Compile();

    // resolve conversion method
    conversion = conversion ?? (x => (TProperty)Convert.ChangeType(x, typeof(TProperty)));

    // convert -> zip -> map
    foreach(var zip in source.Select(conversion).Zip(target, (value, item) => new { item, value })) {
        set(zip.item, zip.value);
    }
}

这个答案的关键部分是如何从getter表达式中create一个setter。