views:

1333

answers:

3

Forgive me if this has been asked before; I did a search but couldn't find anything that specifically answered this question, but I'd be happy to be referred.

I'm taking a peek at both the Entity Framework and LINQ to SQL, and while I like the systems (and of course the LINQ integration) I'm a little skeptical on the data-binding aspect. I've taken query results and inspected them, and they don't appear to implement the standard .NET list-binding interfaces (IBindingList, and more importantly ITypedList), leading me to believe that binding them to a grid (or anything else) is going to use reflection to get/set my entity properties. This seems like a comparatively expensive operation, especially when all of the code is generated anyway and could implement the interfaces.

Does anyone have any insight into this? Is reflection used to get/set the value of the properties? If yes, does this have a performance impact that's noticeable, and does anyone have any idea why they went this route?

Edit

I'm actually concentrating on whether or not ITypedList is implemented somewhere along the way, as that's what has the capability to provide an explicit mechanism for defining and interacting with properties without resorting to reflection. While I didn't have a LINQ to SQL project up, I did inspect a simple Entity Framework entity query result, and it did not appear to implement ITypedList. Does anyone know if I'm just looking at something incorrectly, or if not why this is the case?

Edit 2

After accepting Marc's answer, I thought it might be helpful for others if I posted some simple code I used to seamlessly implement his solution. I put the following in the static constructor for my class:

public static ContextName()
{
    foreach(Type type in System.Reflection.Assembly.GetExecutingAssembly()
        .GetTypes())
    {
        if (type.GetCustomAttributes(typeof(System.Data.Linq.Mapping
            .TableAttribute), true) != null)
        {
            System.ComponentModel.TypeDescriptor.AddProvider(
                new Hyper.ComponentModel.HyperTypeDescriptionProvider(
                    System.ComponentModel.TypeDescriptor.GetProvider(
                        type)), 
                type);
        }
    }
}

While this is for LINQ to SQL, I'm sure an equivalent version could be written for the Entity Framework. This will scan the assembly for any types with the Table attribute and add a custom provider for each of them.

A: 

From looking at what MSDN has to say on LINQ to SQL data binding, it does seem to use IListSource or IBindingList.

Btw, LINQ uses Expression Trees, and that is not reflection as much as meta-programming. Performance should be much better than reflection. Charlie Calvert covers this a bit in this article.

Erich Mirabal
Right, I'm aware that it implements IListSource (and, in the result, IBindingList). The more important interface here is actually ITypedList, as that's what provides the list of PropertyDescriptor objects for each property. Without an explicit implementation of ITypedList (unless I'm missing something), either the BindingList<T> or the BindingSource component has to revert to reflection-based PropertyDescriptors, which will be slower than if they were explicit.
Adam Robinson
Also, unless I have something wrong, the expression trees have more to do with querying the data than they do with retrieving queried data for data binding operations.
Adam Robinson
Yeah, the trees are more for the querying. I just thought it was good to point out just in case. Sorry if it was misleading.
Erich Mirabal
+1  A: 

In my experience with LINQ to SQL, I have concluded for a few reasons that LINQ is using reflection to set and get field values in entity class instances. I don't know if I can remember all the reasons, but here's what I can tell you.

  1. If I recall correctly, LINQ does not call any property procedures, but directly sets and reads all the private field values directly, which can only be done via reflection, as far as I know.
  2. The names provided by the MetaData (in the attributes on the entity class properties) provide field name information in string form (if the database column and property name are different, for example). You can conclude from this that LINQ must be using reflection to look up the member to access it.

I think it does this to enforce simplicity -- you can rely on the values in the fields in the entity class directly mirroring the database column values, and there's not much overhead in retrieving the object from the database (populating a newly created entity to correspond to values retrieved from the database should not be routed through property procedures). One thing I have done to represent enumerated values retrieved from the database, for example, is to make some of the LINQ-generated properties private and wrap them in a manually coded property in a partial class that reads and writes the LINQ property.

BlueMonkMN
+2  A: 

The Expression API that underpins LINQ etc is founded on reflection (MemberInfo), not the component-model (PropertyDescriptor etc) - so there is not a huge requirement for ITypedList. Instead, the contents are inferred from the T in IQueryable<T>, IEnumerable<T> and IList<T> etc.

The closest you might get is IListSource, but that will still just be a shallow wrapper around a proper typed list.

If performance of runtime binding (to PropertyDescriptor) is key, you might want to look at HyperDescriptor - which uses Reflection.Emit and TypeDescriptionProvider to wrap the component-model.

Re the "why" etc; note that in almost all cases with LINQ-to-SQL and EF the Expression (or the "create and set members" part) is going to be compiled to a delegate before it is invoked - so at runtime there is no huge reflection cost. And likewise, with LINQ-to-Objects everything is already compiled (by the C# compiler).

Marc Gravell
Marc, if your HyperDescriptor project works as I'm expecting it to, that will provide exactly what I need. It's still a little confusing to me why Microsoft would not make use of their own databinding infrastructure and rely on the default TypeDescriptor returning ReflectPropertyDescriptors, but oh well. If this works, I don't much care.
Adam Robinson