将自定义类的列表转换为对象数组

时间:2013-11-21 14:38:10

标签: c# excel-dna

我有一个自定义类的列表,其中包含double,string等类型的各种变量。

为了使用Excel DNA将其返回到excel,我需要将列表转换为object[,]

这是我做的,但有更好的方法吗?如果我添加另一个变量,我需要记住重做列数等等。

List<customclass> BMrep = somefunction();
var retdata = new object[BMrep.Count,22];

for (int i = 0; i < BMrep.Count; i++)
{
    retdata[i, 0] = BMrep[i].product_code;
    retdata[i, 1] = BMrep[i].RG;
    ...
}

return retdata;

2 个答案:

答案 0 :(得分:6)

您可以使用反射来获取属性:

var properties = typeof(customclass).GetProperties(BindingFlags.Public | 
                          BindingFlags.Instance).OrderBy(x => x.Name).ToList();

List<customclass> BMrep = somefunction();
var retdata = new object[BMrep.Count, properties.Count];

for (int i = 0; i < BMrep.Count; i++)
{
    for (int j = 0; j < properties.Count; j++)
    {
        retdata[i, j] = properties[j].GetValue(BMrep[i], null);
    }
}

return retdata;

答案 1 :(得分:1)

嗯,Tim S.给了你一个非常可靠的答案。

但是,如果您提到的那些various variables是字段而不是属性,则它将无效。您只需将其更改为GetFields而不是GetProperties(并且GetValue不需要第二个null参数)

这是另一个可以使用字段的例子(使用linq,有点短):

class A
{
    public string Field1;
    public string Field2;
    public string Field3;
}

static void Main(string[] args)
{
    A myA = new A() { Field1 = "rofl", Field2 = "lol", Field3 = "omg" };
    var obj = (from prop in typeof(A).GetFields(BindingFlags.Public | BindingFlags.Instance)
                select prop.GetValue(myA)).ToArray();

    Debug.Assert(obj[0] == "rofl");
    Debug.Assert(obj[1] == "lol");
    Debug.Assert(obj[2] == "omg");
}

如果您希望使用属性,只需将linq替换为:

var obj2 = (from prop in typeof(A).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            select prop.GetValue(myA,null)).ToArray();

我输入var为简短,objobj2类型为Object[]

修改

MSDN指定,

  

GetProperties方法不会按特定顺序返回属性,例如按字母顺序或声明顺序。

因此,如果您想保留订单,可以在字段/属性上创建Attribute,以保留此信息。见下文:

class OrderAttribute : Attribute
{
    public int Order { get; private set; }

    public OrderAttribute(int order)
    {
        this.Order = order;
    }
}

class A
{
    public string FieldWithoutOrder;
    [Order(3)] public string Field1;
    [Order(2)] public string Field2;
    [Order(1)] public string Field3;
}

static void Main(string[] args)
{
    A myA = new A() { Field1 = "rofl", Field2 = "lol", Field3 = "omg", FieldWithoutOrder = "anarchy" };
    var obj = (from prop in typeof(A).GetFields(BindingFlags.Public | BindingFlags.Instance)
               orderby prop.GetCustomAttributes(typeof(OrderAttribute),true).Select(att=>((OrderAttribute)att).Order).DefaultIfEmpty(Int32.MaxValue).First()
               select prop.GetValue(myA)
                ).ToArray();

    var obj2 = (from prop in typeof(A).GetProperties(BindingFlags.Public | BindingFlags.Instance)
               select prop.GetValue(myA,null)).ToArray();

    Debug.Assert(obj[0] == "omg"); //Field3
    Debug.Assert(obj[1] == "lol"); //Field2
    Debug.Assert(obj[2] == "rofl"); //Field1
    Debug.Assert(obj[3] == "anarchy"); //FieldWithoutOrder
}

DefaultIfEmpty指定一个值,以防该字段没有Order属性。

通过这种方式,您可以轻松维护(如果您需要更改字段的顺序,只需更改属性)

我没有为obj2执行此操作,但您可以粘贴相同的orderby语句,它会起作用。

希望它有所帮助。