Is there a good way to avoid using reflection to populate my virtual ListView?

I have it ListViewin virtual mode, and the underlying data is stored in List<MyRowObject>. Each column ListViewcorresponds to a public string property MyRowObject. My columns are ListViewcustomizable at runtime, so any of them can be disabled and can be changed. To return ListViewItemfor an event RetrieveVirtualItem, I have a method similar to:

class MyRowObject
{
    public string[] GetItems(List<PropertyInfo> properties)
    {
        string[] arr = new string[properties.Count];
        foreach(PropertyInfo property in properties)
        {
            arr[i] = (string)property.GetValue(this,null);
        }
        return arr;
    }
}

The event handler for RetrieveVirtualItemlooks like this:

private void listView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    e.Item = new ListViewItem(_virtualList[e.ItemIndex].GetItems(_currentColumns));
}

Perhaps it is not surprising that benchmarking shows that this method is much slower than an implementation that accessed properties directly in hard-coded order, and slowdown is significant enough that I would like to find a better solution.

, , , MyRowObject, , , ( , , , ?).

, ListView - ?

ListView .

+5
5

2

    private List<Func<T, string>> BuildItemGetters<T>(IEnumerable<PropertyInfo> properties)
    {
        List<Func<T, string>> getters = new List<Func<T, string>>();
        foreach (var prop in properties)
        {
            var paramExp = Expression.Parameter(typeof(T), "p");

            Expression propExp = Expression.Property(paramExp, prop);
            if (prop.PropertyType != typeof(string))
                propExp = Expression.Call(propExp, toString);

            var lambdaExp = Expression.Lambda<Func<T, string>>(propExp, paramExp);

            getters.Add(lambdaExp.Compile());
        }

        return getters;
    }

    private string[] GetItems<T>(List<Func<T, string>> properties, T obj)
    {
        int count = properties.Count;
        string[] output = new string[count];

        for (int i = 0; i < count; i++)
            output[i] = properties[i](obj);

        return output;
    }

BuildItemGetters ( , ;) , . GetItems . obj - , - , .

T , :

var props = BuildItemGetters<MyRowObject>(properties);
string[] items = GetItems(props, row);

+3

BindingSource PropertyDescriptor - , , ListView, VirtualMode. , , .

, , ( , ) - http://www.brad-smith.info/blog/archives/104

+1

Reflection.Emit. " ", . CodeProject : http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx.

, , . , , , , InitTypes . , .

0

#, , , - :

  • , "-" , , - ++, vtable getter
  • - >
  • getter .

, , , - CLR/MSIL , .

0

get .

    public class PropertyWrapper<T>
    {
        private Dictionary<string, MethodBase> _getters = new Dictionary<string, MethodBase>();

        public PropertyWrapper()
        {
            foreach (var item in typeof(T).GetProperties())
            {
                if (!item.CanRead)
                    continue;

                _getters.Add(item.Name, item.GetGetMethod());
            }
        }

        public string GetValue(T instance, string name)
        {
            MethodBase getter;
            if (_getters.TryGetValue(name, out getter))
                return getter.Invoke(instance, null).ToString();

            return string.Empty;
        }
    }

:

var wrapper = new PropertyWrapper<MyObject>(); //keep it as a member variable in your form

var myObject = new MyObject{LastName = "Arne");
var value = wrapper.GetValue(myObject, "LastName");
0

All Articles