代码之家  ›  专栏  ›  技术社区  ›  user366312

C#无法将匿名类型分配给-它是只读的

  •  38
  • user366312  · 技术社区  · 15 年前

    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();
        }
    }
    

    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
    

    如何将值重新设置为匿名类型对象?

    3 回复  |  直到 9 年前
        1
  •  67
  •   Gordon Gustafson    15 年前

    obj = new { Name = "asdasd", Price = 11.00 };
    
        2
  •  22
  •   user151323 user151323    15 年前

    匿名类型是使用只读属性创建的。在对象构造之后,不能将其指定给它们。

    Anonymous Types (C# Programming Guide) 关于MSDN:

    匿名类型提供了一种方便的方法,可以将一组只读属性封装到单个对象中,而无需首先显式定义类型。

        3
  •  7
  •   Yannick Motton    15 年前

    匿名类型提供了一种封装一组 只读属性 变成一个 显式定义类型。类型 名称由编译器和 在源代码中不可用 由编译器推断。这个 下面的示例显示了一个匿名 正在用两个参数初始化的类型 名为Amount和Message的属性。

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

        4
  •  6
  •   Adi H    5 年前

    使用 ExpandoObject 相反,因为它支持在对象创建后更新/添加新属性(从C#4开始就存在)。

    dynamic (而不是 var )

    using System.Dynamic;
    
    dynamic person = new ExpandoObject();
    person.FirstName = "John";
    person.LastName = "Doe";
    
        5
  •  0
  •   Jay    4 年前
        /// <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;
        }