Home Dashboard Directory Help
Search

Ability to return strongly-typed anonymous classes by BlueRaja


Status: 

Closed
 as By Design Help for as By Design


8
1
Sign in
to vote
Type: Suggestion
ID: 542278
Opened: 3/16/2010 8:57:06 AM
Access Restriction: Public
2
Workaround(s)
view

Description

By itself, it seems like there should be no reason to return an anonymous class. However, combined with LINQ it becomes vitally important. Consider the following query:

    return (from o in myTable select new {o.column1, o.column2}).Distinct();

This is currently not valid C# due to returning an anonymous class; this makes it nearly impossible to separate the data-retrieval routines from the view. "select o" is often not an option, as in LINQ-to-SQL and LINQ-to-Entities, which will translate that to an unacceptable "SELECT * FROM myTable" SQL-query.

In order to make the above work, the programmer needs to either create a separate class for *every* query they write, or use inconvenient hacks ( http://tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx )

.net 4.0 includes a 'dynamic' keyword which somewhat solves this problem, but we lose compile-time type-checking, intellisense, and suffer decreased performance due to reflection.
Details
Sign in to post a comment.
Posted by BlueRaja on 8/16/2010 at 1:30 PM
That would work, as long as changes to the query were automatically propagated to the auto-generated classes (so we don't have to always change two things).

Of course, from the point of the view of the developer, both of these solutions are exactly the same (just that one is done by the compiler, one by the IDE), so any arguments about which is better for the "public API surface" don't really apply..
Posted by Microsoft on 7/27/2010 at 8:23 PM
Thanks for the comments!

You're right that changes to the public shape of a type used as a return type would similarly affect all places that type is used. The difference there, however, is that it's obvious that you are affecting public surface area when you modify the return types of public properties or methods on a type. After taking an action with that type of obvious breaking-change potential, you'd be likely to do a Find All References and ensure that your uses of that type which still compile still behave as you'd expect.

However, if we allow var as the return type of a method, then a simple change to the middle of a LINQ query can cascade through the end of the query, through multiple following var declarations, and then out as the result of the method, which may now have a totally different type. What seemed like a local tweak to a single method (perhaps even a private helper method!) can then flow through and affect huge swaths of your program, depending on how common this pattern is.

The kind of change we'd be more likely to make here in the future is a richer refactoring library, including a refactoring to change the use of a particular anonymous type into a concrete type. You'd still have the issue of more code in your project, but it could be easily generated for you.

Alex Turner
Program Manager
Visual C# Compiler
Posted by BlueRaja on 7/2/2010 at 8:26 AM
Hey Alex!

Of course, all of those arguments apply to returning explicit types as well - any change to the explicit type will ripple throughout the system to any class that implicitly uses it, changing the API surface, perhaps unintentionally.

In fact, it could be made to compile to exactly the same code, so that the only difference between creating an explicit type for the LINQ query to return and having the compiler implicitly do so is that the explicit case requires significantly more code. Other than that,
    return new {A, B};
could simply be shorthand for what we currently have to do manually:
    return new __ANONYMOUS_TYPE123{A=A; B=B};
}
class __ANONYMOUS_TYPE123 {
    public string A { get; set; }
    public string B { get; set; }
}

Any changes in both cases would result in exactly the same consequences. However, if is too worrisome, we would be okay with only allowing anonymous types to be returned from LINQ queries - that's the only place it's really *needed*, anyways (for the reasons mentioned above)

Thanks for taking the time to hear our suggestions Alex!
-Danny
Posted by Microsoft on 6/18/2010 at 8:37 AM
Thanks for the suggestion for Visual Studio!

When implementing anonymous types and var originally, we considered allowing var in method signatures so that anonymous types could flow naturally beyond method boundaries. However, this generally opens up more brittleness than we feel it is worth in the face of changes to the original method.

Currently, the impact of var is contained to a method body. If you change the statement initializing a var declaration, this can ripple through to other vars recursively, but only in the context of that method body. The fixes needed to get your method to compile again are scoped and local. Once var becomes allowed as a method return type, it's possible for other methods to store that return value as var and then return it, or perhaps IEnumerable<T> where T is the anonymous type, leading this type to flow implicitly far throughout your program.

This means that subtle changes to the body of that original method can now change types throughout your program, including in places where you might not expect it, for example within public interfaces your class library exposes that other developers may have already implemented. Even if you fix up your program to still compile, you may have changed your own API surface in ways that cause breaking changes for others, all without realizing it. While we believe var has great value within methods, we feel that method signatures should always be declared explicitly, with a conscious decision involved whenever they are changed.

Alex Turner
Program Manager
Visual Basic and C# Compiler
Posted by xerocontrol on 3/17/2010 at 8:04 AM
Definitely a good idea and it would be very useful. I wish this could be implemented yesterday.
Posted by Pandincus on 3/17/2010 at 6:19 AM
Good idea; in the past I've used simply POD structures like public struct query1 { public string X { get; set; } public int Y { get; set; } } to store my return values from the query, but it becomes pretty cumbersome when you've got a bunch of queries.
Posted by Microsoft on 3/16/2010 at 7:28 PM
Thank you for your feedback, We are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.
Posted by JaytEkon on 3/1/2011 at 8:41 PM
ImpromptuInterface has the advantage over using dynamic keyword by itself beyond compile-time checking, because when returning an anonymous instance cast to dynamic you have to be careful because accessing properties will fail once it passes and assembly boundary since anonymous classes are internal
Posted by JaytEkon on 3/1/2011 at 8:37 PM
An opensource framework ImpromptuInterface http://code.google.com/p/impromptu-interface/ will let you duck cast an anonymous class instance with interface declared with the same signature. No reflection necessary it uses the DLR.