Передача делегатов с общим типом в качестве параметров метода в C#

#c# #generics #methods #delegates #parameter-passing

Вопрос:

У меня проблема с делегатами и общим типом. Я экспериментирую с делегатами и столкнулся с тем, с чем застрял.

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

 public static class MyClass
{
    public delegate string SerializeAction<T>(T _object);
    public delegate T DeserializeAction<T>(string data);
    public static SerializeAction serializeAction;
    public static DeserializeAction deserializeAction;

    public static void SetupConverter<T>(SerializeAction<T> _serializeFunction, DeserializeAction<T> _deserializeFunction)
    {
       serializeAction = _serializeFunction;
       deserializeAction = _deserializeFunction;
    }        
}
 

Однако я получаю синтаксическую ошибку при объявлении serializeAction and deserializeAction .

Для использования универсального типа ‘SerializeAction’ требуется 1 аргумент типа

Если я использую SerializeAction<T> serializeAction , то он не может найти T . И есть еще одна ошибка. Я создал две функции для тестирования SetupConverter метода.

 class DataJSONConverter
{
    public static string Serialize<T>(T _object) { return JsonSerializer.Serialize(_object); }
    public static T Deserialize<T>(string data) { return JsonSerializer.Deserialize<T>(data); }
}
 

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

 SetupConverter(DataJSONConverter.Serialize, DataJSONConverter.Deserialize);
 

Появляется следующая ошибка:

Аргументы типа для метода «SetupConverter(SerializeAction, DeserializeAction)» не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Итак, что я хочу создать в двух словах: у меня есть MyClass , и у него есть SetupConverter метод. Передавая две функции в качестве аргументов, программист может указать функции преобразования. Позже, если программист вызовет один из методов MyClass , который использует преобразование (например, в этом примере), будут использоваться указанные функции.

 public static void DoSomething<T>(T _object)
{
    string result = serializeAction(_object);
    T _object2 = deserializeAction<T>(result);
}
 

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

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

1. T должно быть объявлено на уровне класса, т. е. public static class MyClass<T> .

2. К сожалению, ни один из ответов не решил мою проблему, я все время сталкивался с проблемой «общего поля», о которой упоминал Метельщик . Тем не менее, я многому научился из ответов, так что большое вам спасибо! Я пересмотрел структуру своей программы и заменил «делегатское решение». Если кто-то хочет достичь такой механики, просто скажите мне, и я сделаю все возможное, чтобы объяснить свое решение! Спасибо за вашу помощь!

Ответ №1:

Если у вас есть класс с двумя универсальными методами Method1<T> и Method2<T> , то ничто не гарантирует, что на самом T деле это один и тот же тип. Звонящий принимает решение.

Если вам нужен универсальный класс, который работает только с одним типом, ваш класс должен быть универсальным, а не вашими методами.

 public static class MyClass<T>
{
    public static Func<T, string> serializeAction;
    public static Func<string, T> deserializeAction;

    public static void SetupConverter(Func<T, string> _serializeFunction, Func<string, T> _deserializeFunction)
    {
       serializeAction = _serializeFunction;
       deserializeAction = _deserializeFunction;
    }        
}
 

Вероятно, вам следует использовать Func<T> тип вместо делегатов.

Ответ №2:

Похоже, вы ищете универсальные поля, но их нет в C#. В качестве обходного пути вы должны сделать MyClass универсальный. Классы тоже могут быть общими!

 // this should be generic
public static class MyClass<T>
{

    // these should not be generic
    public delegate string SerializeAction(T _object);
    public delegate T DeserializeAction(string data);
    private static SerializeAction serializeAction;
    private static DeserializeAction deserializeAction;


    // this should not be generic
    public static void SetupConverter(SerializeAction<T> _serializeFunction, DeserializeAction<T> _deserializeFunction)
    {
       serializeAction = _serializeFunction;
       deserializeAction = _deserializeFunction;
    }

    // this should not be generic
    public static void DoSomething(T _object)
    {
        string result = serializeAction(_object);
        T _object2 = deserializeAction<T>(result);
     }
}
 

Так что скорее, чем

 MyClass.DoSomething<Foo>(someFoo);
 

Вы бы сделали:

 MyClass<Foo>.DoSomething(someFoo);