Есть ли способ, которым Csharp scripting API мог бы выводить типы аргументов, не указывая их?

У меня есть следующий фрагмент кода:

string actionString = "(p1,p2)=>p1.HP-=20";

var options = ScriptOptions.Default.AddReferences(typeof(SimplePlayer).Assembly).AddImports("Player");

var script = CSharpScript.Create<Action<SimplePlayer, SimplePlayer>>(actionString, options);

SimpleDeck d = new SimpleDeck(Game.GameController.Cards, 100, 100);

SimplePlayer p1 = new SimplePlayer(4000, 100, 100, d);
SimplePlayer p2 = new SimplePlayer(4000, 100, 100, d);

var del = script.CreateDelegate();

del.DynamicInvoke(p1, p2);
System.Console.WriteLine(p1.HP);

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

string actionString = "(p1,p2)=>p1.HP-=20";

var options = ScriptOptions.Default.AddReferences(typeof(SimplePlayer).Assembly).AddImports("Player");

var script = CSharpScript.Create(actionString, options);

SimpleDeck d = new SimpleDeck(Game.GameController.Cards, 100, 100);

SimplePlayer p1 = new SimplePlayer(4000, 100, 100, d);
SimplePlayer p2 = new SimplePlayer(4000, 100, 100, d);

var del = script.CreateDelegate();

del.DynamicInvoke(p1, p2);

Меня бросает:

ошибка CS8917: невозможно определить тип делегата.

потому что я не указываю тип, который я хочу создать. Если я изменю код на:

string actionString = "(SimplePlayer p1,SimplePlayer p2)=>p1.HP-=20";

Есть ли способ вывести тип SimplePlayer без явной передачи его в качестве аргумента? И не нужно делать следующее:

var script = CSharpScript.Create<Action<SimplePlayer, SimplePlayer>>(actionString, options);
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вам нужно, чтобы делегаты разрешались во время выполнения (другими словами, без дженериков), одним неуклюжим, но рабочим способом будет процедурная интерполяция в соответствующий тип Action вокруг выражения перед передачей его в CSharpScript. например

string code = Typed(
    "(p1, p2) => p1.HP - 20",
    nameof(SimplePlayer), // first arg type name
    nameof(SimplePlayer) // second arg type name
);
// ((Action<SimplePlayer, SimplePlayer>)((p1, p2) => p1.HP - 20))

static string Typed(string code, params string[] args)
    => $"((Action<{string.Concat(", ", args)}>)({code}))";

Если возвращаемое значение может существовать или не существовать, вы можете так же легко заменить строку.

Редактировать: чтобы использовать любой тип делегата, который вы хотите, и не ограничиваться перегрузками Action, вы можете просто использовать Type.Name в качестве интерполяции. Имейте в виду, что типы с дженериками не будут работать в приведенном ниже примере. Для этого обратитесь к этому ответу.

static string Typed(string code, Type type)
    => $"(({type.Name})({code}))";

Хотя желательно, если у вас есть возможность использовать дженерики, вы можете просто сделать что-то вроде этого.

Run<TDelegate>(string actionString, ScriptOptions options)
    where T : Delegate
{
    var del = CSharpScript.Create<TDelegate>(actionString, options);

    // del is now guaranteed to be 'Delegate' and you can treat it as such, and you can use typeof(T) to do whatever reflection APIs you require
}

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

Rafael Acosta 31.01.2023 20:07

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

Rafael Acosta 01.02.2023 17:14

@RafaelAcosta Я забыл, что правки не уведомляют людей; Я отредактировал этот пост, чтобы отразить то, что вы упомянули.

Emik 03.02.2023 09:09

Эмик очень помогает, спасибо

Rafael Acosta 03.02.2023 15:53

Другие вопросы по теме