В коде есть много вычислений, в зависимости от начальных данных я получаю разный результат. Начальные данные определяются значением ComboBox
, и в итоге в зависимости от этого, к переменной присваивается один из методов внешней библиотеке. Как лучше реализовать это? В итоге, думаю, в зависимости от Combobox
приравнивать переменной string
название метода в библиотеке и использовать reflection
. И в коде, всё, что мне нужно будет менять, это перебор значений Combobox
через switch и присваивание названия методов. Потому что в ComboBox
в итоге будет значений 30-40. Нужно что-то универсальное и лаконичное.
Заведите интерфейс:
public interface IOperation
{
int Execute(int p1, int p2);
}
Вместо статических методов создайте классы, реализующие его:
public class AddOperation : IOperation
{
public int Execute(int p1, int p2)
{
return p1 + p2;
}
}
public class MulOperation : IOperation
{
public int Execute(int p1, int p2)
{
return p1 * p2;
}
}
Тогда, получить список классов, реализующих заданный интерфейс можно примерно так:
var operationTypes =
typeof(Program)
.Assembly.GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IOperation)))
.ToList();
Потом, после выбора нужной операции, создаем ее экземпляр и запускаем:
var operation = (IOperation)Activator.CreateInstance(operationTypes[0]);
Console.WriteLine(operation.Execute(1, 2));
Минус этого подхода (как по мне - незначительный) - эти классы с операциями должны иметь конструктор без параметров.
Другой способ - через рефлексию получить все методы класса/сборки, для того чтобы нужные методы отличить от других можно завести кастомный атрибут:
[AttributeUsage(AttributeTargets.Method)]
public class ExecuteAttribute : Attribute { }
Помечаем нужные методы атрибутом:
public static class Library
{
[Execute]
public static int SumOperation(int p1, int p2)
{
return p1 + p2;
}
[Execute]
public static int MulOperation(int p1, int p2)
{
return p1 * p2;
}
}
Получаем список:
var methods =
typeof(Library)
.GetMethods()
.Where(m => m.GetCustomAttribute<ExecuteAttribute>() != null)
.ToList();
Вызываем нужный:
Console.WriteLine((int)methods[0].Invoke(null, new object[] { 1, 2 }));
Минус этого похода - нет защиты от того, что у метода может быть другая сигнатура и это приведет к ошибке во время исполнения.
При желании в атрибуте можно сделать свойство для указания наименования метода:
[AttributeUsage(AttributeTargets.Method)]
public class ExecuteAttribute : Attribute
{
public string Name { get; }
public ExecuteAttribute(string name)
{
Name = name;
}
}
Тогда, получить имя можно будет так:
var method = methods[0];
string name = method.GetCustomAttribute<ExecuteAttribute>().Name;
А задавать: [Execute("Сложить")]
Ну и для удобства вызова метода можно создать на его основе делегат (спасибо @VladD за подсказку):
var operation = (Func<int, int, int>)Delegate.CreateDelegate(typeof(Func<int, int, int>), method);
Console.WriteLine($"{name} 1 и 2 будет {operation(1, 2)}");
Я бы сделал такую структуру данных:
public class MethodDescription
{
public string Name { get; }
public Action Method { get; }
public MethodDescription(string name, Action method)
{
Name = name;
Method = method;
}
}
Теперь, раз внешняя сборка в ваших руках, она может легко предоставить список всех нужных методов. Например, так:
public static class Methods
{
public static IEnumerable<MethodDescription> All { get; } =
new[]
{
new MethodDescription("First", MyClass.First),
new MethodDescription("Second", MyClass.Second),
new MethodDescription("Very big", MyClass.VeryBig),
new MethodDescription("Not at all", MyClass.NotAtAll)
// добавляйте сюда ещё
};
}
и так далее. Можно также собирать методы не вручную, а через рефлексию.
На клиентской стороне всё получается просто:
<ComboBox ItemsSource="{Binding Source={x:Static extAssembly:Methods.All}}"
DisplayMemberName="Name"/>
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как прикрепить маркер (тоже Image) к PicureBoxImage?
Приложение может запускаться с параметрамиЕсть необходимость вывести хелп с параметрами в этой же консоли, где было запущено приложение,...