C# Anonymous types cannot be assigned to -- it is read only

C#C# 3.0Anonymous Types

C# Problem Overview


What is wrong with this code-snippet?

class Program
{
    static void Main(string[] args)
    {
        var obj = new { Name = "A", Price = 3.003 };
            
        obj.Name = "asdasd";
        obj.Price = 11.00;

        Console.WriteLine("Name = {0}\nPrice = {1}", obj.Name, obj.Price);

        Console.ReadLine();
    }
}

I am getting the following errors:

Error	5	Property or indexer 'AnonymousType#1.Name' cannot be assigned to -- it is read only	.....\CS_30_features.AnonymousTypes\Program.cs	65	13	CS_30_features.AnonymousTypes
Error	6	Property or indexer 'AnonymousType#1.Price' cannot be assigned to -- it is read only	.....\CS_30_features.AnonymousTypes\Program.cs	66	13	CS_30_features.AnonymousTypes

How to re-set values into an anonymous type object?

C# Solutions


Solution 1 - C#

Anonymous types in C# are immutable and hence do not have property setter methods. You'll need to create a new anonmyous type with the values

obj = new { Name = "asdasd", Price = 11.00 };

Solution 2 - C#

Anonymous types are created with read-only properties. You can't assign to them after the object construction.

From Anonymous Types (C# Programming Guide) on MSDN: > Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to first explicitly define a type.

Solution 3 - C#

> Anonymous types provide a convenient way to encapsulate a set of > read-only properties into a single > object without having to first > explicitly define a type. The type > name is generated by the compiler and > is not available at the source code > level. The type of the properties is > inferred by the compiler. The > following example shows an anonymous > type being initialized with two > properties called Amount and Message.

http://msdn.microsoft.com/en-us/library/bb397696.aspx

Solution 4 - C#

Use ExpandoObject instead since it supports updating/adding new properties after object creation (it has been around since since C# 4).

Note that it is important to declare the object using the keyword dynamic (instead of var)

using System.Dynamic;

dynamic person = new ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";

Solution 5 - C#

    /// <summary>
    /// Of 8 bytes.
    /// A structure which represents an:
    /// <see cref="System.Object"/>, <see cref="System.Array"/> or <see cref="System.String"/>.
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit, Size = 8)]
    public struct Invariant
    {
        [System.Runtime.InteropServices.FieldOffset(0)]
        public System.ValueType Value;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public System.Array Array;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public object Object;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public string String;

        /// <summary>
        /// Used to interpret the address/memory of object which can be thought of as IntPtr*
        /// Remember to deference the type 1 time to inspect the memory where ref object points to.
        /// </summary>
        /// <typeparam name="TType"></typeparam>
        /// <param name="index"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public System.Span<TType> GetSpan<TType>(int index, int length) => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref System.Runtime.CompilerServices.Unsafe.Add(ref System.Runtime.CompilerServices.Unsafe.As<object, TType>(ref Object), index), length);

        /// <summary>
        /// Get a <see cref="System.IntPtr"/> which points to the address of <see cref="Object"/>
        /// </summary>
        /// <returns></returns>
        public System.IntPtr ToPointer() => GetSpan<System.IntPtr>(0, 1)[0] + System.IntPtr.Size + System.IntPtr.Size; //Syncbloc, Rtti

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool IsAligned() => (ulong)ToPointer() % (ulong)System.IntPtr.Size == 0;

        /// <summary>
        /// Allowing one to set the <see cref="System.Type"/> of <see cref="Object"/>
        /// </summary>
        public System.Type Type
        {
            set
            {
                System.Runtime.InteropServices.Marshal.WriteIntPtr(GetSpan<System.IntPtr>(0, 1)[0], value.TypeHandle.Value);
                //System.Runtime.CompilerServices.Unsafe.AsRef(System.Runtime.CompilerServices.Unsafe.As<object, System.IntPtr>(ref Object)) = value.TypeHandle.Value;
                //System.Runtime.CompilerServices.Unsafe.AsRef(GetSpan<System.IntPtr>(0, 1)[0]) = value.TypeHandle.Value;
            }
        }
    }

    /// <summary>
    /// A single value
    /// Will implicitly convert to <see cref="Invariant"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public ref struct Invariant<T>
    {
        public static System.RuntimeTypeHandle TypeHandle => typeof(T).TypeHandle;

        public static System.IntPtr ToPointer(ref T t)
        {
            System.IntPtr rtti = System.Runtime.CompilerServices.Unsafe.As<T, System.IntPtr>(ref t);

            //rtti = System.Runtime.InteropServices.Marshal.ReadIntPtr(rtti, 0);

            return rtti;
        }

        /// <summary>
        /// The value
        /// </summary>
        public T Value;

        /// <summary>
        /// Implicit create <see cref="Invariant"/>
        /// </summary>
        /// <param name="src"></param>

        public static implicit operator Invariant(Invariant<T> src) => new Invariant() { Object = src.Value };

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static T Emplace(ref Invariant invariant, bool writeHeader) => Emplace(invariant.ToPointer(), writeHeader);

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static T Emplace(ref Invariant invariant) => Emplace(invariant.ToPointer(), false == System.Type.GetTypeFromHandle(TypeHandle).IsValueType);//Might need to read the void* in the spann which is is different places depending on the runtime.

        /// <summary>
        /// Emplace the value initializing the Object header and TypeHandle.
        /// </summary>
        /// <param name="bufferPtr"></param>
        /// <returns></returns>
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static T Emplace(System.IntPtr bufferPtr, bool writeHeader = true)
        {
            var dataPointer = bufferPtr + 1;

            //New way
            if (writeHeader) System.Runtime.CompilerServices.Unsafe.AsRef(in bufferPtr) = System.IntPtr.Zero;
            System.Runtime.CompilerServices.Unsafe.AsRef(in dataPointer) = typeof(T).TypeHandle.Value;

            //Old way
            //if (writeHeader) System.Runtime.InteropServices.Marshal.WriteIntPtr(bufferPtr, System.IntPtr.Zero); //Object Header
            //System.Runtime.InteropServices.Marshal.WriteIntPtr(dataPointer, typeof(T).TypeHandle.Value);

            return System.Runtime.CompilerServices.Unsafe.As<System.IntPtr, T>(ref dataPointer); //Pointer to the method table pointer
        }

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static T Emplace(ref T t, bool writeHeader = true) => Emplace(System.Runtime.CompilerServices.Unsafe.AsRef(in System.Runtime.CompilerServices.Unsafe.As<T, System.IntPtr>(ref t)), writeHeader);
        
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static T Emplace(ref T t) => Emplace(ref t, false == System.Type.GetTypeFromHandle(TypeHandle).IsValueType);

        /// <summary>
        /// Useful when ref t has been Emplaced
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="t"></param>
        /// <param name="arguments"></param>
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static void Construct(System.Linq.Expressions.Expression<System.Action> expression, ref T t, params object[] arguments)
        {
            //figure out which constructorInfo
            System.Linq.Expressions.NewExpression newExpression = expression.Body as System.Linq.Expressions.NewExpression;

            //newExpression.Arguments
            //DeclaringType should equal typeof(T)
            //typeof(T).GetConstructor(System.Array.Empty<System.Type>()).Invoke(t, arguments);
            //don't read the object returned here its on the stack and boxed refer to t
            if (null == arguments) arguments = System.Array.Empty<object>();
            newExpression.Constructor.Invoke(t, arguments);
            //Could get paramters from expression
            var instantiator = System.Linq.Expressions.Expression.Lambda/*<System.Func<T>>*/(newExpression).Compile();
            instantiator.Method.Invoke(t, arguments);
        }

        //[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        //public unsafe static T Alloc(System.Span<byte> bytes) => Alloc((System.IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref bytes.GetPinnableReference()));

        //Could be exposed from a static Construct<T>(ref T) method but which constructor to invoke?
        //Could also accept an Expression and use the expression to build a delegate
        //Alloc(()=>new Whatever(1,2,3,"4"));
        //When you have the expression the call to the correct MethodInfo (constructor) is already performed via overload resolution.
        //
        //private static unsafe class Constructor
        //{
        //    private static readonly delegate*<T, void> ConstructorHandle;

        //    static Constructor()
        //    {
        //        System.Type type = typeof(T);

        //        System.Reflection.ConstructorInfo constructorInfo = type.GetConstructor(System.Array.Empty<System.Type>());

        //        Constructor.ConstructorHandle = (delegate*<T, void>)constructorInfo.MethodHandle.GetFunctionPointer();
        //    }

        //    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        //    internal static void Invoke(T returnObject)
        //    {
        //        Constructor.ConstructorHandle(returnObject);
        //    }
        //}

        /// <summary>
        /// Creates a <see cref="System.Span{T}"/>
        /// </summary>
        /// <returns></returns>
        public System.Span<T> GetSpan() => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref Value, 1);

        /// <summary>
        /// Create a <see cref="System.Span{TType}"/>
        /// </summary>
        /// <typeparam name="TType"></typeparam>
        /// <param name="index"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public System.Span<TType> GetSpan<TType>(int index, int length) => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref System.Runtime.CompilerServices.Unsafe.Add(ref System.Runtime.CompilerServices.Unsafe.As<T, TType>(ref Value), index), length);
    }

/// <summary>
/// Provides extensions useful for <see cref="System.Span{T}"/>
/// </summary>
public static class SpanExtensions
{
    /// <summary>
    /// Pointer to the first element
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="span"></param>
    /// <returns></returns>
    public static System.IntPtr ToPointer<T>(this System.Span<T> span)
    {
        //ptr to struct to interior ptr
        ref T pp = ref span[0];
        ref byte b = ref System.Runtime.CompilerServices.Unsafe.As<T, byte>(ref pp);

        //Interior pointer layout and size may vary with such
        //Object header is 24 bytes and 1 more pointer for the interior ptr itself
        b = ref System.Runtime.CompilerServices.Unsafe.Add(ref b,(System.IntPtr)(-System.IntPtr.Size * 4));

        //from bite to pointer
        ref System.IntPtr ptrSpan = ref System.Runtime.CompilerServices.Unsafe.As<byte, System.IntPtr>(ref b);
        return ptrSpan;
    }

    public static int ReadLength(ref System.IntPtr ptr) => System.Runtime.InteropServices.Marshal.ReadInt32(ptr, System.IntPtr.Size);

    public static System.Span<T> RecoverSpan<T>(System.IntPtr ptr)
    {
        //Because of reloc on the stack 1 must keep 2 pts, 1 to the length and 1 to the last element
        var pb = ptr + (System.IntPtr.Size * 4);
        ref byte reverse = ref System.Runtime.CompilerServices.Unsafe.As<System.IntPtr, byte>(ref pb);
        ref T pp = ref System.Runtime.CompilerServices.Unsafe.As<byte, T>(ref reverse);
        System.Span<T> span = System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref pp, System.Runtime.InteropServices.Marshal.ReadInt32(ptr, System.IntPtr.Size));
        return span;
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser366312View Question on Stackoverflow
Solution 1 - C#JaredParView Answer on Stackoverflow
Solution 2 - C#user151323View Answer on Stackoverflow
Solution 3 - C#Yannick MottonView Answer on Stackoverflow
Solution 4 - C#Adi HView Answer on Stackoverflow
Solution 5 - C#JayView Answer on Stackoverflow