Что-то похожее на "использование", которое создаст объект и вызовет метод, когда это будет сделано, но позвольте мне сделать то, что я хочу между ними

Я использую Lidgren и для каждого нового типа сообщений, которые я делаю, в итоге я пишу один и тот же код. Я создаю экземпляр NetOutgoingMessage, запуская на нем различные вызовы назначения, а затем отправляя его, когда я закончил. Создание и отправка одинаковы, поэтому я хочу написать оболочку, чтобы сделать это для меня, но это класс sealed, а не IDisposable. То, что я делаю, это что-то вроде:

NetOutgoingMessage om = server.CreateMessage();

om.Write(messageType);
om.Write(data1);
om.Write(data2);

server.SendMessage(om, server.Connections, NetDeliveryMethod.UnreliableSequenced, 0);

И я хочу сделать что-то вроде:

using(AutoNetOutgoingMessage om(server, messageType, NetDeliveryMethod.UnreliableSequenced))
{
    om.Write(data1);
    om.Write(data2);
}

Очевидно, я не могу сделать using, так есть ли другой общий способ, если вы реализуете такие функции? Я не ищу невероятно сложное решение, так как это просто поддержка для меня, поэтому у меня нет проблем с повторением кода для каждого сообщения. Но мне любопытно, есть ли забавный трюк С#, о котором я не знаю.

Ответы

Ответ 1

Да, вы можете легко обеспечить такую ​​временную взаимосвязь между некоторыми вызовами, получив делегат, который содержит пользовательские действия, и вызывая этот делегат именно тогда, когда вы хотите.

Вот пример:

void MyMethod(Server server, Action<NetOutgoingMessage> action)
{
    NetOutgoingMessage om = server.CreateMessage();
    action(om);
    server.SendMessage(om, server.Connections, NetDeliveryMethod.UnreliableSequenced, 0);     
}

Назовите его следующим образом:

MyMethod(server, om => {
    om.Write(data1);
    om.Write(data2);
});

По существу, это форма инверсия управления: практика, посредством которой общая часть кода вызывает внешнюю, специализированную фрагмент кода в указанной точке.

Как правило, это достигается с помощью (часто абстрактных) классов или интерфейсов - и совершает через них виртуальные вызовы. Делегаты и lambdas просто позволяют вам выражать одно и то же более кратко, в то время как компилятор выполняет скучную работу (например, объявляет новый класс, захватывая требуемые переменные) за кулисами.

Ответ 2

Создайте обертку вокруг класса NetOutgoingMessage, который реализует IDisposable.

public class AutoMessage : IDisposable
{
    private const NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced;

    public NetPeer Peer { get; private set; }

    public List<NetConnection> Recipients { get; private set; } 

    public NetOutgoingMessage Message { get; private set; }

    public AutoMessage(NetPeer peer, List<NetConnection> recipients)
    {
        Peer = peer;
        Recipients = recipients;
        Message = peer.CreateMessage();
    }

    public void Dispose()
    {
        Peer.SendMessage(Message, Recipients, method, 0);
    }
}

Затем вы можете использовать его через using:

var data = 123;
using (var msg = new AutoMessage(Client, Client.Connections))
{
    msg.Message.Write(data);
}

Другой вариант - создать интерфейс IMessage, который имеет определения методов для Encode и Decode, и разрешить другим классам реализовывать их. Затем создайте метод Send, который будет писать тип сообщения и запустить метод Encode. Это то, что я делаю с собственными приложениями, и он отлично работает.