2

我有一个自定义类的列表,其中包含 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;
4

2 回答 2

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;
于 2013-11-21T14:43:40.083 回答
1

Well, Tim S. gave you a pretty solid answer.

However, if those various variables you mentioned are fields and not properties, it won't work. You could just change it to GetFields instead of GetProperties (and GetValue wouldn't need the second null parameter)

Here's another example which would work with fields (using linq, a bit shorter):

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

If you'd like it to work with properties, just replace the linq with this:

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

I typed var to be short but obj and obj2 are of type Object[]

EDIT:

As specified by MSDN,

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order.

So if you want to keep the order, you could create an Attribute on the field/property which could keep this information. See below:

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
}

The DefaultIfEmpty specifies a value in case the field doesn't have the Order Attribute.

This way it'll be easy for you to maintain (if you need to change the order of the fields, just change in the attribute)

I didn't do it for obj2 but you can paste the same orderby statement and it'll work.

Hope it helps.

于 2013-11-21T14:54:37.340 回答