Как работают атрибуты входа и выхода в .NET?

Я пытался сериализовать массив через границу 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 при сериализации класса? И действительно ли они вызывают передачу параметра по ссылке или просто копируется содержимое?


person g t    schedule 30.01.2012    source источник


Ответы (1)


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

Некоторый код для игры:

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;
    }
}
person Hans Passant    schedule 31.01.2012
comment
Отлично, спасибо! Я никогда раньше не слышал об этих атрибутах, но проблема, с которой я столкнулся, была бы почти неразрешима без атрибута [Out]. К счастью, я заметил их в dotPeek/ILSpy. Кажется удивительным, что массивы также не маршалируются обратно, так как теперь мне нужно обернуть весь класс классом, у которого есть метод с атрибутами. Жаль, что их нельзя применить со стороны вызывающего абонента... - person g t; 31.01.2012
comment
Проверяя далее, многие классы Stream в пространстве имен System имеют параметр 'buffer' их метода Read(), отмеченный атрибутами [In] [Out]. Интересно, должны ли NegotiateStream и SslStream в System.IO также иметь эти атрибуты, поскольку их нет в .NET 4. - person g t; 31.01.2012