C#无法将匿名类型分配给--它是只读的
这段代码有什么问题C#无法将匿名类型分配给--它是只读的,c#,c#-3.0,anonymous-types,C#,C# 3.0,Anonymous Types,这段代码有什么问题 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.Pric
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
如何将值重新设置为匿名类型对象?匿名类型是使用只读属性创建的。在对象构造之后,不能将其指定给它们 从MSDN开始: 匿名类型提供了一种方便的方法,可以将一组只读属性封装到单个对象中,而无需首先显式定义类型 匿名类型提供了一种封装一组 只读属性转换为单个 对象而不必首先 显式定义类型。类型 名称由编译器和 在源代码中不可用 水平。属性的类型为 由编译器推断。这个 下面的示例显示了一个匿名 正在用两个参数初始化的类型 名为Amount和Message的属性 C#中的匿名类型是不可变的,因此没有属性设置器方法。您需要使用以下值创建一个新的anonmyous类型
obj = new { Name = "asdasd", Price = 11.00 };
改为使用,因为它支持在对象创建后更新/添加新属性(自C#4以来就一直存在)
请注意,使用关键字dynamic
(而不是var
)声明对象非常重要
//
///有8个字节。
///表示以下内容的结构:
///,或。
///
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit,大小=8)]
公共结构不变量
{
[System.Runtime.InteropServices.FieldOffset(0)]
公共系统价值类型价值;
[System.Runtime.InteropServices.FieldOffset(0)]
公共系统.阵列;
[System.Runtime.InteropServices.FieldOffset(0)]
公共客体;
[System.Runtime.InteropServices.FieldOffset(0)]
公共字符串;
///
///用于解释对象的地址/内存,可将其视为IntPtr*
///请记住,在检查ref对象指向的内存时,要遵守type 1的时间。
///
///
///
///
///
public System.Span GetSpan(int index,int length)=>System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref-System.Runtime.CompilerServices.Unsafe.Add(ref-System.Runtime.CompilerServices.Unsafe.As(ref-Object),index),length);
///
///获取一个指向的地址
///
///
public System.IntPtr ToPointer()=>GetSpan(0,1)[0]+System.IntPtr.Size+System.IntPtr.Size;//Syncbloc,Rtti
///
///
///
///
public bool IsAligned()=>(ulong)ToPointer()%(ulong)System.IntPtr.Size==0;
///
///允许一个人设置
///
公共系统.类型
{
设置
{
System.Runtime.InteropServices.Marshal.WriteIntPtr(GetSpan(0,1)[0],value.TypeHandle.value);
//System.Runtime.CompilerServices.Unsafe.AsRef(System.Runtime.CompilerServices.Unsafe.As(ref对象))=value.TypeHandle.value;
//System.Runtime.CompilerServices.Unsafe.AsRef(GetSpan(0,1)[0])=value.TypeHandle.value;
}
}
}
///
///单一值
///将隐式转换为
///
///
公共引用结构不变量
{
public static System.RuntimeTypeHandle TypeHandle=>typeof(T).TypeHandle;
公共静态系统.IntPtr拓扑互连(参考T)
{
System.IntPtr rtti=System.Runtime.CompilerServices.Unsafe.As(参考t);
//rtti=System.Runtime.InteropServices.Marshal.ReadIntPtr(rtti,0);
返回rtti;
}
///
///价值
///
公共价值观;
///
///隐式创建
///
///
公共静态隐式运算符不变量(不变量src)=>new Invariant(){Object=src.Value};
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
公共静态T放置(ref Invariant,bool writeHeader)=>放置(Invariant.ToPointer(),writeHeader);
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
public static T Emplace(ref Invariant)=>Emplace(Invariant.ToPointer(),false==System.Type.GetTypeFromHandle(TypeHandle.IsValueType);//可能需要读取spann中的void*,根据运行时,它位于不同的位置。
///
///放置初始化对象标题和类型句柄的值。
///
///
///
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
public static T Emplace(System.IntPtr bufferPtr,bool writeHeader=true)
{
var dataPointer=bufferPtr+1;
//新方式
if(writeHeader)System.Runtime.CompilerServices.Unsafe.AsRef(在bufferPtr中)=System.IntPtr.Zero;
System.Runtime.CompilerServices.Unsafe.AsRef(在数据指针中)=typeof(T).TypeHandle.Value;
//老路
//if(writeHeader)System.Runtime.InteropServices.Marshal.WriteIntPtr(bufferPtr,System.IntPtr.Zero);//对象头
//System.Runtime.InteropServices.Marshal.WriteIntPtr(数据指针,typeof(T.TypeHandle.Value));
返回System.Runtime.CompilerServices.Unsafe.As(ref-dataPointer);//指向方法表指针的指针
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
public static T Emplace(ref T,bool writeHeader=true)=>Emplace(System.Runtime.CompilerServices.Unsafe.AsRef(in System.Runtime.Comp
using System.Dynamic;
dynamic person = new ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";
/// <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;
}