проблема с пониманием шаблона в c# и функции

#c# #templates #async-await #stride

Вопрос:

сеть документации и самая важная документация: SocketMessageLayer

в SocketMessageLayer есть функция, которую я не знаю, как вызвать: public void AddPacketHandler<T>(Func<T, Task> asyncHandler, bool oneTime = false)

и вот как я пытался это назвать:

     string str = "example";
    public SimpleSocket SS = new SimpleSocket();
    public SocketMessageLayer SML;
    
    
    
    public void Server(){
        //int port, bool singleConnection, int retryCount = 1
        SS.StartServer(21, false, 1);
        SML = new SocketMessageLayer(SS, true);
    }
    public void Client(){
        //string address, int port, bool needAck = true
        SS.StartClient("127.0.0.1", 21, true);
        SML = new SocketMessageLayer(SS, false);
    }
    
    
    
    public async Task SendMessage(string str){
        //public void AddPacketHandler<T>(Func<T, Task> asyncHandler, bool oneTime = false)
        await SML.AddPacketHandler<string>(SomeFunction("ClientSendToServer", await SML.Send(str) ), false  );
        //await SML.Send(str);
        
    }
    
    
    public void SomeFunction(string s, Task Tas){
        str = s;
    }
 

проблема Argument 2: cannot convert from 'void' to 'System.Threading.Tasks.Task' в отправке сообщения

то, что я пытаюсь сделать, — это отправить сообщение на сервер или с сервера на клиент. и у меня проблемы с пониманием основ.

Комментарии:

1. спасибо, но если я это сделаю, я получу: cannot convert from 'void' to 'System.Action<string>'

Ответ №1:

Здесь есть ряд проблем.

AddPacketHandler ожидает Func<T, Task> делегата в качестве первого параметра, но вы вызываете SomeFunction его, а не передаете как делегат.

Это означает, что вы пытаетесь передать возвращаемое значение SomeFunction т. е. void, что недопустимо, следовательно, ошибка компиляции.

Кроме того, Func<T, Task> является делегатом, который принимает один аргумент типа T и возвращает a Task .

Ваш SomeFunction метод принимает два аргумента типа T и Task и возвращает void , поэтому он не может быть преобразован в a Func<T, Task> и не может быть передан в качестве первого параметра.

Что вы могли бы сделать, так это изменить подпись SomeFunction на эту:

 public Task SomeFunction(string s)
{
    str = s;
    return Task.CompletedTask;
}
 

Который может быть передан следующим образом:

 public async Task SendMessage(string str)
{
    SML.AddPacketHandler<string>(SomeFunction, false);
    await SML.Send(str);        
}
 

И вы, вероятно, захотите перейти "ClientSendToServer" к SendMessage этому методу, а не жестко его кодировать:

 await SendMessage("ClientSendToServer");
 

Ответ №2:

Первый и самый важный: почему вы должны вызывать AddPacketHandler?

Глядя на это, обработчик пакетов не является обязательным, поэтому вы не можете добавлять его, если он вам не нужен, хотя для регистрации обработчика пакетов вы можете сделать это множеством способов, вот три примера:

Пример 1

 public class Program
    {
        private static List<Func<object, Task>> _handlers = new List<Func<object, Task>>();

        public static async Task Main(string[] args)
        {
            // you handler code goes here
            Func<string, Task> func = (str) => Task.Run(() => Console.WriteLine(str));           

            AddPacketHandler(func);
            await _handlers[0]("foo");
        }       

        public static void AddPacketHandler<T>(Func<T, Task> asyncHandler)
        {
            _handlers.Add((obj) => asyncHandler((T)obj));
        }
    }

 

Пример 2

 public class Program
    {
        private static List<Func<object, Task>> _handlers = new List<Func<object, Task>>();

        public static async Task Main(string[] args)
        {
            // you can create your handler here
            AddPacketHandler<string>(
                (str) =>
                {
                    return Task.Run(() => Console.WriteLine(str));
                });
            await _handlers[0]("foo");
        }

        public static void AddPacketHandler<T>(Func<T, Task> asyncHandler)
        {
            _handlers.Add((obj) => asyncHandler((T)obj));
        }
    }
 

Пример 3

 public class Program
    {
        private static List<Func<object, Task>> _handlers = new List<Func<object, Task>>();

        public static async Task Main(string[] args)
        {
            AddPacketHandler<string>(SomeFunction);         
            await _handlers[0]("foo");
        }

        // you handler code goes here
        private static Task SomeFunction(string s)
        {
            return Task.Run(() => Console.WriteLine(s));
        }

        public static void AddPacketHandler<T>(Func<T, Task> asyncHandler)
        {
            _handlers.Add((obj) => asyncHandler((T)obj));
        }
    }
 

Сам дескриптор будет вызван библиотекой здесь

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