0

C# anonymous types seem really useful, but I've pretty immediately hit upon an application where I would like to set the property of an anonymous type, and I'd also like to be able to use attributes.

My application is a general purpose stored procedure and SQL executor, which can automatically map C# properties to SQL input and output paramaters with appropriate SqlDbType (e.g. string maps to NVARCHAR(MAX), etc.).

e.g.

    int PersonID = 1234;
    var output = new { GivenName = (string)null, FamilyName = (string)null };
    sqlExecutor.ExecSQL("SELECT @GivenName = GivenName, @FamilyName = FamilyName FROM People WHERE PersonID = @PersonID", new { PersonID }, output);
    string GivenName = output.GivenName;
    string FamilyName = output.FamilyName;

The approach works (also for stored procedures, I just used raw SQL in the above to make it clearer what I am trying to do). But I can only make it work, in exactly the form above, by using the 'bad idea' of setting the backing fields in the anonymous output object (using code in the answer by user Alex to How to set value for property of an anonymous object?).

I can't think of any other way to create such an easy to use, lightweight interface for this kind of problem. It's pretty easy to see that attributes might be useful here too, e.g. to modify the parameter mapping.

So why are anonymous types limited to no setting and no attributes? Those both seem as if they would be useful in reasonable use-cases, and as if they would be easy features to include, given that the basic anonymous type feature is already in the language.

Community
  • 1
  • 1
MikeBeaton
  • 3,314
  • 4
  • 36
  • 45
  • 3
    Would `dynamic` work better here? – Nate Barbettini Jun 10 '16 at 15:42
  • 1
    As with all language features, this probably _could_ be made to work in the compiler. But there's always costs associated too. Then think about what the syntax might look like to do this - by the time you've shoehorned in whatever would be needed to mark your anonymous type in such a fashion, you may as well just create a class anyway. – James Thorpe Jun 10 '16 at 15:45
  • In addition to what James said also I think that if you need more then you should go with an explicit named class...I saw too much unreadable code in Java because of (highly abused) anonymous types. Leave them for dirty local cases... – Adriano Repetti Jun 10 '16 at 15:50
  • 1
    Anonymous type properties are read only, they can not be set. – Explisam Jun 10 '16 at 15:52
  • 1
    The main reason is so that they can be used as key values in groupings, joins, etc. Is there a reason you don't just create an actual type that _can_ have attributes? If you want to propose a syntax for a _mutable_ anonymous type then feel free to post it on http://connect.microsoft.com. – D Stanley Jun 10 '16 at 15:53
  • @James Thorpe I think there would be essentially no costs at all to enabling the setter, since the backing field and the getter are definitely already there? The syntax for attributes I think could also be very straight forward and natural, c.f.: http://stackoverflow.com/questions/1217437/can-i-use-attributes-with-anonymous-classes – MikeBeaton Jun 10 '16 at 15:54
  • Also note from Eric Lippert's answer in the duplicate that it is _possible_ (in fact VB has that feature) but the risks of a mutable type outweigh the benefits in their opinion. – D Stanley Jun 10 '16 at 15:57
  • 1
    @bmju Yes it's _technically_ possible to have mutable anonymous types, but there are downsides - the biggest of which is the use as a hash key, which was one of the driving forces behind the feature in the first place. – D Stanley Jun 10 '16 at 15:59
  • @bmju Read all of the answers - they give the reasons why they _chose_ to make them immutable. I don't think I can give any better reasons other than regurgitating the reasons they give. – D Stanley Jun 10 '16 at 16:01
  • To be fair, though, I reopened the question. – D Stanley Jun 10 '16 at 16:01
  • Read the last part [Anonymous Types (C# Programming Guide)](https://msdn.microsoft.com/en-us/library/bb397696.aspx) – Explisam Jun 10 '16 at 16:01
  • @Nate Barbettini Thank you for the suggestion. I did try a dynamic `ExpandoObject`, and it associates a typed value with a name, which doesn't work for me (I don't think?) in the case where the value can be null. – MikeBeaton Jun 10 '16 at 16:12
  • @D Stanley This is the post with Eric Lippert's answer: http://stackoverflow.com/questions/9043848/non-read-only-alternative-to-anonymous-types Thanks for the heads up about that, and for the other useful info which you've given here. – MikeBeaton Jun 13 '16 at 09:37

1 Answers1

0

Probably you could hack yourself into another solution here, like modifying the generated code of the anonymous class / instance via reflection rewriting or using dynamic stuff like ExpandoObject and/or Dictionary. But here is a cleaner and simpler way - the 'with expression' - which offers 'non-destructive mutation'. It keeps the 'type' and still allows you to mutate the anonymous object (actually it copies everything into a new object (if some of your anonymous type props are reference types, a reference is copied).

The with expression is only supported for - particularly anonymous types - in C# 10, which means .NET 6 framework. So the solution here is only available for the newer solution type. Many of us are stuck with legacy code way back in .NET Framework 4.8 and so on in real world solutions at work.. If you can use C# 10 and .NET 6 at work, consider yourself lucky as you have a mightier toolbelt at hand with C# !

You can from C# 10 use the with expression for anonymous types (and structs and in C# 9 on for records).

Example:

Paste into Linqpad 7: this code in a C# Program and .NET set to Auto

void Main()
{
    var someInstanceOfAnonymousType = new {
     Knight = "Sir Galahad",
     FavoriteColor = "Blue. No RED!",
     Shout = "Aaaargh!"
    }; 
    
    var mutatedInstanceOfAnonymousType = someInstanceOfAnonymousType with
    { Knight = "Sir Lancelot", Shout = "I did not vote for you!" };
    
    mutatedInstanceOfAnonymousType.Dump(); 
}

Note that the with operator will maintain your anonymous type and still let you in an easy way modify any number of backing fields exposed as readonly properties in the anonymous type. Just type on the RHS the instance followed with a 'with' followed with the curly braces and the properties with values you want to set.

Mutating anonymous typed instance with with expression

Tore Aurstad
  • 3,189
  • 1
  • 27
  • 22
  • If you use a tool like IlSpy you can find the 'hidden fields' via reflection and mutate them. This is not recommended at all, just to illustrate it is possible. var knightField = mutatedInstanceOfAnonymousType.GetType().GetField("i__Field", BindingFlags.NonPublic | BindingFlags.Instance); knightField.SetValue(mutatedInstanceOfAnonymousType, "Sir Gawain"); – Tore Aurstad Apr 12 '22 at 22:08