Как атрибуты In и Out работают в .NET? - PullRequest
10 голосов
/ 31 января 2012

Я пытался сериализовать массив через границу AppDomain, используя следующий код:

public int Read(byte[] buffer, int offset, int count)
{
    return base.Read(buffer, offset, count);
}

Вероятно, после того, как я заметил атрибуты в других местах, я пометил параметры метода атрибутами [In] и [Out], которые, казалось, заставляли параметры вести себя так, как если бы они были переданы по ссылке.

Например:

public int Read([In, Out] byte[] buffer, int offset, int count)
{
    return base.Read(buffer, offset, count);
}

До того, как я добавил атрибуты, содержимое переменной buffer было потеряно после возврата из метода через границу AppDomain.

Класс (SslStream) наследуется от MarshalByRefObject, но не помечен атрибутом Serializable. Это единственный способ сделать параметр передаваемым по значению? Эти атрибуты как-то распознаются .NET при сериализации класса? И действительно ли они вызывают передачу параметра по ссылке или просто копируется содержимое?

1 Ответ

12 голосов
/ 31 января 2012

Это очень плохо документированная функция .NET Remoting. Это не имеет никакого отношения к тому, является ли ваш класс [Serializable] или производным от MarshalByRefObject. Здесь возникает вопрос, как аргумент маршалируется через границу домена приложений. Сам звонок сделан под капот с помощью Remoting. Массивы , а не автоматически возвращаются после вызова, что явно повышает производительность. Требуется только атрибут [Out], подразумевается [In]. Я не смог найти соответствующую документацию по этому вопросу в MSDN, просто сообщение в блоге от кого-то, кто столкнулся с той же проблемой (прокрутите вниз до "Использование OutAttribute в Remoting").

Код для игры:

using System;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        var ad = AppDomain.CreateDomain("second");
        var t = (Test)ad.CreateInstanceAndUnwrap(typeof(Test).Assembly.FullName, typeof(Test).FullName);
        var b = new byte[] { 1 };
        t.Read(b);
        System.Diagnostics.Debug.Assert(b[0] == 2);
    }
}

class Test : MarshalByRefObject {
    public void Read([Out]byte[] arg) {
        arg[0] *= 2;
    }
}
...