Determine whether type is anonymous?

A

Anders Borum

Hi,

I'm working with Expression Trees right now (building a QueryProvider), and
I was wondering how to determine if a type is anonymous (i.e. the result of
a projection). The first thought was to parse the type for known
"identifiers" (i.e. "<>" and "Anonymous"), but it feels like a flaky
solution. I've found a blog post that provides a sample method doing this
(http://www.liensberger.it/web/blog/?p=191), but wanted to ask here as well.

Anybody up to answering that? :)
- and merry christmas to all of you!
 
P

Patrice

IMO the first step would be to explain what you'll do with this information.

Ultimately an anonymous type is just a type whose name has been
automatically assigned by the compiler so for now I don't see what you'll
want to do once you know that (and anonymous types are unrelated with the
result of a projection, they can be used for other purpose and a projection
could be of a well known type).

Do you want to find out out the type of elements returned by a query ?
 
P

Peter Duniho

Anders said:
Hi,

I'm working with Expression Trees right now (building a QueryProvider),
and I was wondering how to determine if a type is anonymous (i.e. the
result of a projection). The first thought was to parse the type for
known "identifiers" (i.e. "<>" and "Anonymous"), but it feels like a
flaky solution. I've found a blog post that provides a sample method
doing this (http://www.liensberger.it/web/blog/?p=191), but wanted to
ask here as well.

Anybody up to answering that? :)

Well, I think the blog post provides the necessary caveats. In C#, the
basic heuristic should work accurately for a known version of the
compiler. The type names aren't legal for hand-written code, so either
the types were generated by the compiler or someone has written a
special-purpose compiler to generate the types (begging the question why
anyone would do that, especially to allow someone to explicitly name a
type with the same pattern as an anonymous type).

But it's an undocumented, implementation-specific naming scheme. The
actual name chosen by the C# compiler is left to the compiler, and can
change from compiler to compiler, as well as from one version of a given
compiler to another.

As Patrice hints at, the question of whether a type is anonymous or not
should be irrelevant. What do you care whether it's anonymous? In what
way does that help your own code work better? It seems like checking
for an anonymous type would be akin to checking user-defined types for
proper naming conventions and handling them differently according to how
they were named.

In general, anonymous types and their instances shouldn't be escaping
the method in which they are used in the first place. If and when they
do, it's a strong indicator that the code ought to be using a named type
anyway. But even if they do escape, to handle anonymous types
differently from named types doesn't seem very useful either.

Pete
 
A

Anders Borum

Hi Patrice,

thanks for taking the time to reply, but I'm afraid you've missed the
question completely! :)
IMO the first step would be to explain what you'll do with this
information.

I guess that would require a lot of writing, but basically, I'm writing a
QueryProvider that allows expressions against IQueryable business models to
be translated/mapped to internal entities exposed by LINQ to SQL/EF (which
is the DAL). Because I need to trim for security on the result set (once
enumeration occours - and this can't be done in DB), I need to know whether
the resulting type is a projection or not. If it's a projection, I'll have
to translate the Select() expression to a standard Select() expression, and
use the lambda (that holds the projection of T) to yield the correct type
back when enumerating .. long story, as you can imagine, but it's working
nicely, and I'm adding support for compiled queries and so forth.

I annotate the business models (and their members) with attributes to map to
the correct internal entity type (and member, if there's an mismatch). When
I translate the incoming expression tree, the goal is to end up with the
similar expression targetting LINQ to SQL/EF - and, like I said, it's
working nicely, is very flexible and supports a wide range of features
already.

Basically I'm on top of it, except for the small part of recognizing the
anonymous types, however, I could just go the other way around and recognize
"known" types, such as "strings, structs (value types), and business
models"; if the type differs from that, it's a projection - end result is
the same, and I guess, better.
Ultimately an anonymous type is just a type whose name has been
automatically assigned by the compiler so for now I don't see what you'll
want to do once you know that (and anonymous types are unrelated with the
result of a projection, they can be used for other purpose and a
projection could be of a well known type).

I'm well aware of how anonymous types works, who create them and so forth,
and I was simply asking if there was a property or the like on a reflection
type that I had missed (I guess that was also the essense of my question).
Do you want to find out out the type of elements returned by a query ?

No, that information is readily available from the expression tree (as
generic parameters to IEnumerable<T> or IEnumerable<IGrouping<T, K>> etc.).
 
A

Anders Borum

Hi Pete,

thanks for the lenghy reply!
Well, I think the blog post provides the necessary caveats. In C#, the
basic heuristic should work accurately for a known version of the
compiler. The type names aren't legal for hand-written code, so either
the types were generated by the compiler or someone has written a
special-purpose compiler to generate the types (begging the question why
anyone would do that, especially to allow someone to explicitly name a
type with the same pattern as an anonymous type).

I have to agree with you on that one, but I was getting curious.
In general, anonymous types and their instances shouldn't be escaping the
method in which they are used in the first place. If and when they do,
it's a strong indicator that the code ought to be using a named type
anyway. But even if they do escape, to handle anonymous types differently
from named types doesn't seem very useful either.

Well, they're not really escaping the method in which they're used, but in
this situation they're a result of a projection that leads to different code
paths in my QueryProvider (when translating results from the underlying DAL
to business objects, or, a projection (or value types, in case of Count()
etc.).

Please see my reply to Patrice for a quick overview of what the project is
all about.
 
P

Peter Duniho

Anders said:
[...]
Basically I'm on top of it, except for the small part of recognizing the
anonymous types, however, I could just go the other way around and
recognize "known" types, such as "strings, structs (value types), and
business models"; if the type differs from that, it's a projection - end
result is the same, and I guess, better. [...]

Your call. As you say, maybe with more elaboration it would be clear to
us why this is something you need.

But, something being "a projection" and something using "an anonymous
type" are ideas orthogonal to each other. Anonymous types can be used
for other things than projections, and a projection need not use an
anonymous type (and in fact, with the new "Tuple" generic classes coming
out, I would expect more projections to _not_ use anonymous types).

If you _really_ need to know whether something is a projection or not
(i.e. yielded from a Select() statement), checking for an anonymous type
isn't reliable. In fact, it's probably a LOT less reliable than any
heuristic for identifying anonymous types in the first place.

Pete
 
P

Patrice

thanks for taking the time to reply, but I'm afraid you've missed the
question completely! :)

Yes, sorry but I still don't see how anonymous type and projection are
related. To me they seems to be just unrelated (couldn't a projection just
return a known type such as a string ?). Have you tried to use the heuristic
described in the article you saw to fist see if it works. You'll be always
able to switch the "IsAnonymous" implementation if you find something better
(but I don't see how it will work if it doesn't return an anonymous type
which is IMO perfectly possible)...
I guess that would require a lot of writing, but basically, I'm writing a
QueryProvider that allows expressions against IQueryable business models
to be translated/mapped to internal entities exposed by LINQ to SQL/EF
(which is the DAL). Because I need to trim for security on the result set
(once enumeration occours - and this can't be done in DB), I need to know
whether the resulting type is a projection or not. If it's a projection,
I'll have to translate the Select() expression to a standard Select()
expression, and use the lambda (that holds the projection of T) to yield
the correct type back when enumerating .. long story, as you can imagine,
but it's working nicely, and I'm adding support for compiled queries and
so forth.

So don't you try to find out which type is returned by the lambda that is
used by the Select call ? (which is not necessarily an anonymous type).

I'm not sure about that but If I remember I saw that there is also some
query interception features (don't remember if I saw this perhaps in EF 4 or
..NET RIA Services). For now my understanding is that you don't want to write
a full featured provider but that you want to "intercept" the query to add
security related checks...

Perhaps a small sample would help :

Data[] Source = {new Data{a="Albert",b="B",c="C"},new
Data{a="Alfred",b="B2",c="C2"}};
var q1 = from data in Source where data.a.StartsWith("A") select
(double) 1;
var q2 = from data in Source select new { data.a, data.b };

// I would like to find out types ? for q1 and ? for q2 ?

For now my understanding is that when you parse the expression tree you want
tyo find out :
Debug.WriteLine(q1.AsQueryable().ElementType.ToString());
Debug.WriteLine(q2.AsQueryable().ElementType.ToString());

But perhaps more likely that you want to trigger something when you encouter
the Select method call (as in the first case, you could find the double type
multiple times in the query in a context in whihc you are not interested at
all).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top