Non-read only alternative to anonymous types

前端 未结 6 1511
误落风尘
误落风尘 2020-11-29 09:02

In C#, an anonymous type can be as follows:

method doStuff(){
     var myVar = new {
         a = false, 
         b = true
     }

     if (myVar.a) 
     {         


        
相关标签:
6条回答
  • 2020-11-29 09:28

    No, you'll have to create your own class or struct to do this (preferrably a class if you want it to be mutable - mutable structs are horrible).

    If you don't care about Equals/ToString/GetHashCode implementations, that's pretty easy:

    public class MyClass {
        public bool Foo { get; set; }
        public bool Bar { get; set; }
    }
    

    (I'd still use properties rather than fields, for various reasons.)

    Personally I usually find myself wanting an immutable type which I can pass between methods etc - I want a named version of the existing anonymous type feature...

    0 讨论(0)
  • 2020-11-29 09:29

    I find it really annoying that you can't set anonymous properties as read/write as you can in VB - often I want to return data from a database using EF/LINQ projection, and then do some massaging of the data in c# that can't be done at the database for whatever reason. The easiest way to do this is to iterate over existing anonymous instances and update properties as you go. NOTE this is not so bad now in EF.Core, as you can mix db functions and .net functions in a single query finally.

    My go-to workaround is to use reflection and will be frowned upon and down-voted but works; buyer beware if the underlying implementation changes and all your code breaks.

    public static class AnonClassHelper {
    
        public static void SetField<T>(object anonClass, string fieldName, T value) {
            var field = anonClass.GetType().GetField($"<{fieldName}>i__Field", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    
            field.SetValue(anonClass, value);
        }
    
    }
    // usage
    AnonClassHelper.SetField(inst, nameof(inst.SomeField), newVal);
    

    An alternative I have used when dealing with strings is to make properties of type StringBuilder, then these individual properties will be settable via the StringBuilder methods after you have an instance of your anonymous type.

    0 讨论(0)
  • 2020-11-29 09:37

    For the above types of operation, you should define your own mutable STRUCT. Mutable structs may pose a headache for compiler writers like Eric Lippert, and there are some unfortunate limitations in how .net handles them, but nonetheless the semantics of mutable "Plain Old Data" structs (structs in which all fields are public, and the only public functions which write this are constructors, or are called exclusively from constructors) offer far clearer semantics than can be achieved via classes.

    For example, consider the following:

    struct Foo {
      public int bar; 
      ...other stuff;
    }
    int test(Action<Foo[]> proc1, Action<Foo> proc2)
    {
      foo myFoos[] = new Foo[100];
      proc1(myFoos);
      myFoos[4].bar = 9;
      proc2(myFoos[4]); // Pass-by-value
      return myFoos[4].bar;
    }
    

    Assuming there's no unsafe code and that the passed-in delegates can be called and will return in finite time, what will test() return? The fact that Foo is a struct with a public field bar is sufficient to answer the question: it will return 9, regardless of what else appears in the declaration of Foo, and regardless of what functions are passed in proc1 and proc2. If Foo were a class, one would have to examine every single Action<Foo[]> and Action<Foo> that exists, or will ever exist, to know what test() would return. Determining that Foo is a struct with public field bar seems much easier than examining all past and future functions that might get passed in.

    Struct methods which modify this are handled particularly poorly in .net, so if one needs to use a method to modify a struct, it's almost certainly better to use one of these patterns:

      myStruct = myStruct.ModifiedInSomeFashion(...);  // Approach #1
      myStructType.ModifyInSomeFashion(ref myStruct, ...);  // Approach #2
    

    than the pattern:

      myStruct.ModifyInSomeFashion(...);
    

    Provided one uses the above approach to struct-modifying patterns, however, mutable structs have the advantage of allowing code which is both more efficient and easier to read than immutable structs or immutable classes, and is much less trouble-prone than mutable classes. For things which represent an aggregation of values, with no identity outside the values they contain, mutable class types are often the worst possible representation.

    0 讨论(0)
  • 2020-11-29 09:38

    You won't be able to get the nice initialization syntax but the ExpandoObject class introduced in .NET 4 would serve as a viable solution.

    dynamic eo = new ExpandoObject();
    
    eo.SomeIntValue = 5;
    eo.SomeIntValue = 10; // works fine
    
    0 讨论(0)
  • 2020-11-29 09:40

    Is there an alternative to anonymous types which will allow me to concisely define a simple "record" type like this without making it read-only?

    No. You'll have to make a nominal type.

    If no, is there something fundamentally wrong with wanting to do this?

    No, it's a reasonable feature that we have considered before.

    I note that in Visual Basic, anonymous types are mutable if you want them to be.

    The only thing that is really "fundamentally wrong" about a mutable anonymous type is that it would be dangerous to use one as a hash key. We designed anonymous types with the assumptions that (1) you're going to use them as the keys in equijoins in LINQ query comprehensions, and (2) in LINQ-to-Objects and other implementations, joins will be implemented using hash tables. Therefore anonymous types should be useful as hash keys, and mutable hash keys are dangerous.

    In Visual Basic, the GetHashCode implementation does not consume any information from mutable fields of anonymous types. Though that is a reasonable compromise, we simply decided that in C# the extra complexity wasn't worth the effort.

    0 讨论(0)
  • 2020-11-29 09:45

    In C# 7 we can leverage named tuples to do the trick:

    (bool a, bool b) myVar = (false, true);
    
    if (myVar.a)
    {
        myVar.b = true;
    }
    
    0 讨论(0)
提交回复
热议问题