Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# protobuf net如何处理只读字段?_C#_Protobuf Net_Readonly_Il - Fatal编程技术网

C# protobuf net如何处理只读字段?

C# protobuf net如何处理只读字段?,c#,protobuf-net,readonly,il,C#,Protobuf Net,Readonly,Il,我使用protobuf net对数据进行序列化/反序列化 我有一些相当简单的类,所以这不是真正的问题 据我所知,ProtobufNet使用IL生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用IL写入这样的字段?我可以清楚地看到它工作得很好,但我不知道为什么 我试着在代码中发现它,但它有点太复杂了 我自己尝试生成这样的代码总是导致IL验证器错误。事实上,我不能让它失败——至少在内存中生成时是这样 让我们简单地从一个公共只读字段开始(这样我们就不会违反任何可访问性规则);

我使用protobuf net对数据进行序列化/反序列化

我有一些相当简单的类,所以这不是真正的问题

据我所知,ProtobufNet使用IL生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用IL写入这样的字段?我可以清楚地看到它工作得很好,但我不知道为什么

我试着在代码中发现它,但它有点太复杂了


我自己尝试生成这样的代码总是导致IL验证器错误。

事实上,我不能让它失败——至少在内存中生成时是这样

让我们简单地从一个
公共只读
字段开始(这样我们就不会违反任何可访问性规则);我的第一次尝试如下,效果很好:

using System;
using System.Reflection;
using System.Reflection.Emit;
class Foo
{
    public readonly int i;
    public int I { get { return i; } }
    public Foo(int i) { this.i = i; }
}
static class Program
{
    static void Main()
    {
        var setter = CreateWriteAnyInt32Field(typeof(Foo), "i");
        var foo = new Foo(123);
        setter(foo, 42);
        Console.WriteLine(foo.I); // 42;
    }
    static Action<object, int> CreateWriteAnyInt32Field(Type type, string fieldName)
    {
        var field = type.GetField(fieldName,
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        var method = new DynamicMethod("evil", null,
            new[] { typeof(object), typeof(int) });
        var il = method.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, type);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stfld, field);
        il.Emit(OpCodes.Ret);
        return (Action<object, int>)method.CreateDelegate(typeof(Action<object, int>));
    }
}
上面的代码给出了非常模糊的答案:

操作可能会使运行时不稳定

但我们通过假装该方法在字段的声明类型中来解决这个问题:

var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(int) }, field.DeclaringType);
通过启用
skipVisibility
,可以完成其他一些内部检查:

var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(int) }, field.DeclaringType, true);

但是,请注意,如果生成独立程序集,并非所有这些都是可能的。在创建实际DLL时,您需要遵守更高的标准。因此,
预编译器
工具(用于预生成程序集)无法处理与内存元编程代码相同的场景范围。

由于我对本次讨论非常感兴趣,我尝试了Marc Gravell的示例代码并。。。它在MS.NET 4.0上抛出
VerificationException

我已经设法使它工作,但我需要使用
DynamicMethod
构造函数,将
owner
参数设置为
字段。DeclaringType
即使在公共
I
字段的情况下也是如此<代码>SkipVisibility参数在这种情况下似乎是多余的


另外,我认为这个条目应该是一个注释,但由于缺少代表,我无法对其他人的答案进行注释。

我会立即检查它。也许我的问题与只读字段没有严格的关系。有趣的是,我的代码在Mono上运行,而在.NET.Doh上不运行。我未能提供DeclaringType。但现在我想知道,为什么它会起作用?只读字段不应该只能从对象的构造函数写入吗?不管怎样,谢谢你的回答。@PiotrZierhoffer很多东西只在编译器上强制执行,并且完全
PEVerify
。最终,您可以通过反射更改
只读
字段,序列化器/物化器通常会完全跳过构造函数,因此如果是这种情况,则无法分配值。应该注意的是,动态方法不允许在完全信任上下文(即普通桌面应用程序)中进行IL验证。因此,如果你能用一种动态的方法做一些事情,那并不能证明它是合法的。如果您的代码正在做一些无法验证的事情(不安全,甚至完全没有意义),JIT无论如何都会很乐意编译它。我将此报告为bug(),但MS拒绝提供验证动态方法的方法。我没有运行Marc的代码,只是对其进行了分析,但这一点似乎是正确的。
var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(int) }, field.DeclaringType, true);