【问题标题】:Difference in buffer size of inline delegate内联委托的缓冲区大小差异
【发布时间】:2019-07-09 07:03:00
【问题描述】:

我在使用内联函数时遇到了这种情况。这在我心中提出了几个问题。
示例 1:(全局 testDeligate)

[Serializable]
class TestClass
{
    Func<int, int> testDeligate = (a) => { a = +10; a = +20; return a; };
    public void testMethod()
    {
        int xx = 10;
        if (xx == 1)
        {
            testDeligate(10);
            return;
        }
        else if (xx == 2)
        {
            testDeligate(20);
            return;
        }
        else if (xx == 3)
        {
            testDeligate(33);
            return;
        }
        return;
    }
}  

示例 2:(本地 testDeligate)

[Serializable]
class TestClass
{
    public void testMethod()
    {
        Func<int, int> testDeligate = (a) => { a = +10; a = +20; return a; };
        int xx = 10;
        if (xx == 1)
        {
            testDeligate(10);
            return;
        }
        else if (xx == 2)
        {
            testDeligate(20);
            return;
        }
        else if (xx == 3)
        {
            testDeligate(33);
            return;
        }
        return;
    }
}  

在计算 TestClass 的缓冲区大小时,我得到了不同的响应。

    TestClass testClass = new TestClass();
    var bf = new BinaryFormatter();
    var ms = new MemoryStream();
    bf.Serialize(ms, testClass);
    var size = ms.Length;  

示例 1:大小 = 1308
示例 2:大小 = 127
我无法弄清楚这两种情况下缓冲区大小存在差异的原因。

【问题讨论】:

  • 没有成员的序列化类的缓冲区总是小于有成员的序列化类的缓冲区
  • 二进制序列化通过序列化类的字段来工作。示例 2 没有字段。示例 1 变得强大不仅是因为 testDeligate 字段,而且它还必须序列化 C# 编译器生成的不可见类以实现 lambda 表达式。请注意这是多么脆弱,序列化的数据很容易在代码更改时变得无效。
  • @HansPassant 因此最好使用在方法中定义的内联函数?

标签: c# .net oop


【解决方案1】:

After MSDN(强调我的):

序列化是将对象转换为字节流以存储对象或将其传输到内存、数据库或文件的过程。 其主要目的是保存对象的状态,以便能够在需要时重新创建它。

成员方法显然不是对象的状态。它属于对象的类型。此类的每个对象都将具有相同的方法,因此序列化它没有意义。因此,对于您的第二个示例,序列化程序仅缓冲元数据以区分序列化对象的类型,因为它就是全部。

然而,在您的第一个示例中,您有一个动态分配的委托成员。它是一个成员字段,可以在类中轻松操作。没有什么能阻止你编写类似

的代码
class MyClass
{
    Func<int, int> testDeligate = (a) => { a = +10; a = +20; return a; };
    public void MutateMe()
    {
        testDelegate = (a) => 10 * a;
    }
}

在这种情况下,委托成员的值对象状态的一部分。因此,序列化程序需要对进入分配的 lambda 实现的所有数据进行编码。

请注意,如果您将字段更改为 static,您将获得与示例 2 相同的大小。再次,因为该字段将不再是对象状态的一部分,而是 @987654324 @类型的一部分。

您可能想知道如果将字段更改为 readonly 会发生什么 - 答案是什么,它仍然需要序列化(与示例 1 的效果相同。),因为它仍然可以在运行时,例如在 ctor 中,所以它仍然是对象状态的一部分。

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 2014-06-10
    • 2014-09-20
    • 2015-06-05
    • 2013-11-02
    相关资源
    最近更新 更多