Tech Off Thread

15 posts

LINQ Question

Back to Forum: Tech Off
  • User profile image
    Secret​Software

    Error    2    Property or indexer 'AnonymousType#1.MyAnnoymousP' cannot be assigned to -- it is read only  

    Why did this became like this as we go from Beta 1 to Beta 2?

    This code generated the above error

    var q = from x in y
                 where x.d = 1
                 select new {MyAnnoymousP = x.L, x.J};

    q.MyAnnoymousP = Something;

    in beta 1 this was valid, but in Beta 2 it became ReadOnly. Why? Will this change? Is this a bug in Beta 2?

    Thnx:)



  • User profile image
    littleguru

    I can help you with that. They marked all the fields as readonly and removed the getter of the properties. They did it, because they implemented GetHashCode() on the values of the properties and they needed the instance to be immutable for that...

    More is found on my connect bug report about that issue.

    Won't be changed in the final version!

  • User profile image
    wkempf

    SecretSoftware wrote:
    Error    2    Property or indexer 'AnonymousType#1.MyAnnoymousP' cannot be assigned to -- it is read only  

    Why did this became like this as we go from Beta 1 to Beta 2?

    This code generated the above error

    var q = from x in y
                 where x.d = 1
                 select new {MyAnnoymousP = x.L, x.J};

    q.MyAnnoymousP = Something;

    in beta 1 this was valid, but in Beta 2 it became ReadOnly. Why? Will this change? Is this a bug in Beta 2?

    Thnx:)





    littleguru gave a good answer, but I'd like to point out that your code above has several bugs and won't even compile.  I realize this is example code typed on the fly, so I'm not trying to be a "code cop", but until I read the answer from littleguru I couldn't even figure out what you thought was wrong. [C]

  • User profile image
    Secret​Software

    littleguru wrote:
    I can help you with that. They marked all the fields as readonly and removed the getter of the properties. They did it, because they implemented GetHashCode() on the values of the properties and they needed the instance to be immutable for that...

    More is found on my connect bug report about that issue.

    Won't be changed in the final version!


    Thanks for your reply LittleGuru. I read the bug report you filed, and I am upset by this change.

    There is a solution to this problem [I have 50 classes with 200 + lines of code that has LINQ in preparation for final Go Live linceses]. They can implement something like string class. Editing would mean remove old value and add new value, just like in strings. The HashTable would just point to a new reference value as if this value was added through hashtable.add (x,y). and the old value would be removed by its Key.

    Would this not work as in when we edit a String?

    This bug really broke many lines of code for me and its like a nightmare senario.

  • User profile image
    Secret​Software

    wkempf wrote:
    
    SecretSoftware wrote:
    Error    2    Property or indexer 'AnonymousType#1.MyAnnoymousP' cannot be assigned to -- it is read only  

    Why did this became like this as we go from Beta 1 to Beta 2?

    This code generated the above error

    var q = from x in y
                 where x.d = 1
                 select new {MyAnnoymousP = x.L, x.J};

    q.MyAnnoymousP = Something;

    in beta 1 this was valid, but in Beta 2 it became ReadOnly. Why? Will this change? Is this a bug in Beta 2?

    Thnx:)





    littleguru gave a good answer, but I'd like to point out that your code above has several bugs and won't even compile.  I realize this is example code typed on the fly, so I'm not trying to be a "code cop", but until I read the answer from littleguru I couldn't even figure out what you thought was wrong. [C]


    Yes, this is only example code on the fly. I just wanted to show that when you try to reassign the q.MyAnnonmousP to a new value Something, it will cause compiler error.

    I used to be able to do this in Beta 1, but now they made them immutable, and I think they should allow us to edit them like we edit strings which are immutables in .NET (Ie, when edit a value, remove old one and add new one). this way every one is happy?.

  • User profile image
    Secret​Software

    Looks like they will fix it

    I am confused:)

    Paul Vick's blog Post

    C# Team Blog about it


    And This Blog



    I like Paul's Idea, I hope they fix this, because I do not want to rewrite code again Sad.

  • User profile image
    Sven Groot

    Paul Vick's post applies only to VB, not to C#. It looks like anonymous types will remain immutable in C#.

  • User profile image
    littleguru

    SecretSoftware wrote:
    Thanks for your reply LittleGuru. I read the bug report you filed, and I am upset by this change


    I had to change my ORM to work with dynamic types... Usually i create an instance of an object (you can even specify a factory for it) and set the property values afterwards. For anonymous types I had to change that to call the constructor with the values...

    Btw. does somebody know how to detect if a type is an anonymous type? I have seen that there is the CompilerGeneratedAttribute set on them and that they have a weird name, but is there any other thing I could do... There's no property on the type that returns true for an anonymous type? - I haven't found one so far Sad

  • User profile image
    Secret​Software

    littleguru wrote:
    
    SecretSoftware wrote:
    Thanks for your reply LittleGuru. I read the bug report you filed, and I am upset by this change


    I had to change my ORM to work with dynamic types... Usually i create an instance of an object (you can even specify a factory for it) and set the property values afterwards. For anonymous types I had to change that to call the constructor with the values...

    Btw. does somebody know how to detect if a type is an anonymous type? I have seen that there is the CompilerGeneratedAttribute set on them and that they have a weird name, but is there any other thing I could do... There's no property on the type that returns true for an anonymous type? - I haven't found one so far



    But the whole point of anonymous types is that they are anonymous, where their type is not important to know, and you just want a class that holds data groups together.

    However, You can make a property when you construct it. And modify to work with your specific logic? There might be a way using reflection, but I am not sure about this though.

    var cust1 = new { Name = "LittleGuru", Address = "Planet Earth" ,

    IsAnonymousType = true};


    Edit: You could do this?

    var cust1 = new { Name = "LittleGuru", Address = "Planet Earth" };
    if (cust1.GetType().ToString().Contains("AnonymousType"))
    Console.WriteLine("Yes!!");
    else
    Console.WriteLine("NO!!");
    Console.ReadLine();










  • User profile image
    littleguru

    Yeah. I know that. I'm using reflection with anonymous types already. But if you look inside an assembly (at the IL) you'll see that they are named <>anonymous_something and have the "CompilerGeneratedAttribute" on top of them. It's not very nice because

    1) the name is generated by the compiler. The VB.NET compiler could name them different than the C# one.
    2) The CompilerGeneratedAttribute is put on everything that is created by the compiler.

    I need a way to say: THIS is 100% a dynamic type and this isn't, which doesn't seem to be possible right now.

    Filed it as issue: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296989

  • User profile image
    bdesmet

    A few answers that might be useful. In C# 3.0 anonymous types are immutable indeed; there are only getters while the properties can only be set through the constructor (which is created by the compiler). In VB 9.0 anonymous types are mutable except for fields marked with the Key keyword. This is the addition Paul Vick was referring to.

    Concerning detection of anonymous types, you're right there's no metadata available that ensures a type is a dynamically cooked up type, neither is there an API to help you out (which wouldn't give any guarantuees anyhow if there's no dedicated piece of metadata). A good heuristic to determine anonymous types is:

    - Check for the CompilerGeneratedAttribute using reflection
    - Type name contains "AnonymousType"
    - Type name starts with either "<>" or "VB$" (these prefixes cannot be used by code written by a developer)
    - Type is generic
    - Type definition is private (and sealed in C# 3.0)

    The code below illustrates this:

    static TypeAttributes s_ta = TypeAttributes.NotPublic;

    static bool IsAnonymousType(Type t)
    {
        return    t.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length == 1
               && t.IsGenericType
               && t.Name.Contains("AnonymousType") 
               && (t.Name.StartsWith("<>") || t.Name.StartsWith("VB$"))
               && (t.Attributes & s_ta) == s_ta;
    }

    An alternative is to construct a regex to check the name to be valid against C# 3.0 or VB 9.0 anonymous type naming conventions - which unfortunately aren't official by any means.

    Enjoy!

  • User profile image
    littleguru

    I don't want rely on a heuristic. Next comes another language and names them otherwise and I'm in trouble again... There should be something build in to make that easy. Like a naming convention or something: like with an enum - there are very clear statements how they should look like.

  • User profile image
    Ion Todirel

    littleguru wrote:
    does somebody know how to detect if a type is an anonymous type?
    why would you want that for?

  • User profile image
    littleguru

    Ion Todirel wrote:
    
    littleguru wrote:
    does somebody know how to detect if a type is an anonymous type?
    why would you want that for?


    I need it in my O/RM... I'm in contact with a guy from Microsoft now. Let's see how this turns out.

  • User profile image
    bdesmet

    Ion Todirel wrote:
    
    littleguru wrote:
    does somebody know how to detect if a type is an anonymous type?
    why would you want that for?


    Well, a possible use is in the creation of custom LINQ query providers that are aiming to achieve some intelligence level. Say you have a query like this:

    var res1 = from p in products select new { p.Name, p.Price = p.UnitPrice }

    Now assume you're using this query as the basis for another query (which results in calling IQueryProvider's CreateQuery method again, causing to 'extend' the current query's expression tree), like this:

    var res2 = from p in res1 orderby p.Price descending select new { p.Name, Discount = p.Price * 0.05 }

    In this second query, you're referring to p.Price, which in reality is the original datasource's (i.e. variable product) p.UnitPrice 'column'. With anonymous types, your query provider could figure this out since it has the guarantee that what comes in to the anonymous type from the first query will be the same as what comes out when using it in a second query. Therefore, projections based on anonymous types are the only real gateways towards smart providers that allow some level of composability. So, when iterating over res2, the composed query above could be translated into one single query statement rather than one that goes to the server and another one that's executing in a LINQ to Objects fashion (sample assuming we're targeting SQL):

    SELECT [Name], 0.05 * [UnitPrice] AS [Discount] FROM Products ORDER BY [UnitPrice] DESCENDING

    On the other hand, assume you have something like this:

    var res1 = from p in products select new MyProduct(p.Name, p.UnitPrice)

    Now, if you start to write a query against res1's results, there's no way to get to know where p.Name and p.UnitPrice have gone through. Maybe MyProduct has properties with similar names, but that's not enough. Even if you'd use this:

    var res1 = from p in products select new MyProduct { p.Name, Price = p.UnitPrice }

    and refer to MyProduct's Name or Price property subsequently, there's no guarantee whatsoever that values assigned to those properties are retrieved immutably.

    So, to wrap up: an intelligent query parser could benefit from the knowledge that anonymous types expose certain semantics wrt their properties, while types provided by the developer herself put an end to query intelligence (and therefore composability).

    P.S. I've been working on some of this stuff lately on a query parser that I want to be quite intelligent; I've the same problem as littleguru mentioned but am using the heuristic I posted here at the moment to detect anonymous types.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.