Разница в размере буфера встроенного делегата - PullRequest
0 голосов
/ 09 июля 2019

Я пришел к этому сценарию, когда использовал встроенную функцию. Которые подняли несколько вопросов в моей голове.
Пример 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: (Local 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
Я не могу выяснить причину, почему существует разница в размере буфера в обоих сценариях.

1 Ответ

1 голос
/ 09 июля 2019

После MSDN (выделено мое):

Сериализация - это процесс преобразования объекта в поток байтов для хранения объекта или передачи его в память, базу данных или файл. Его основная цель - сохранить состояние объекта , чтобы иметь возможность воссоздать его при необходимости.

Метод-член, очевидно, не является состоянием объекта. Это относится к типу объекта. У каждого объекта этого класса будет один и тот же метод, поэтому нет смысла его сериализовывать. Так что для вашего второго примера сериализатор буферизует только метаданные, чтобы различать тип сериализованного объекта, поскольку это все, что есть.

В вашем первом примере, однако, у вас есть динамически назначенный член делегата. Это поле члена, которым можно легко манипулировать в классе. Ничто не мешает вам писать код вроде

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

В этом случае значение члена делегата составляет часть состояния вашего объекта. Таким образом, сериализатору необходимо кодировать все данные, которые поступают в реализацию назначенной лямбды.

Обратите внимание, что если вы измените поле на static, вы снова получите тот же размер, что и, например, 2., так как поле больше не будет частью состояния объекта, а будет static часть типа.

Вы можете задаться вопросом, что произойдет, если вы измените поле на readonly - ответ - ничто, его все равно нужно будет сериализовать (такой же эффект, как в примере 1.), поскольку он все еще может быть динамически вычислен в время выполнения, например в ctor, так что он все еще будет частью состояния объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...