如何在c#中指定插件函数的默认值
本文关键字:插件 函数 默认值 | 更新日期: 2023-09-27 18:15:08
我正在尝试实现一个简单的插件系统,它将允许人们写以下内容:
[Plugin("A plugin function")]
public static int PluginFunction(int a, int b)
{
return a + b;
}
,然后将包含此函数的DLL放到一个文件夹中,应用程序将对其进行扫描,并在运行时显示为可用函数。这一切都很好,到目前为止一切都很好,PluginAttribute类是你所期望的,只是一个函数的描述字符串。
然而,我希望允许插件作者为参数指定默认值。这是OK的值在编译时是恒定的,然后通过反射推断,但我想有一种方法来指定默认值为更复杂的类型,将在运行时创建。有人实现过类似的东西吗?主要目标是使实现插件功能变得简单-我试图避免复杂的脚手架,但如果我想要这个功能,我接受我漂亮的简单系统不会削减它。我也很高兴在应用程序代码中有一些复杂性,这使得系统在插件作者看来很简单。
谢谢,查理。
更新:
我将使用这里建议的组合,最接近的是Peter O.提出的-这是一个版本:
[Plugin("A plugin function")]
[Defaults(typeof(AdderDefaults))]
public static int Adder(int a, int b)
{
return a + b;
}
public static class AdderDefaults
{
public static int a { get { return 1; } }
public static int b { get { return 2; } }
}
[Plugin("Another plugin function")]
[Defaults(typeof(TexturizerDefaults))]
public static Bitmap Texturize(Bitmap source, Point offset)
{
return result;
}
public static class TexturizerDefaults
{
// no default for source parameter
public static Point offset { get { return new Point(16, 16); } }
}
允许跳过参数并通过名称指定参数。没有编译时检查,但没关系-在运行时检查这些是可以接受的。
也许您可以创建一个引用类型的属性包含插件的默认值。例子:
[PluginDefaults(typeof(MyPluginDefaults))]
类MyPluginDefaults可能看起来像:
public class MyPluginDefaults {
int Parameter1 { // First parameter
get { return 0; } // default value for 'a'
}
int Parameter2 { // Second parameter
get { return 4; } // default value for 'b'
}
// Additional parameters would be called Parameter3, Parameter4, and so on.
}
有很多方法可以做到这一点,最简单的是使用一个简单的约定:
[Plugin("A plugin function")]
public static int PluginFunction(int a, int b)
{
return a + b;
}
public static object[] PluginFunctionDefaultArguments()
{
return new [] { 0, 0 };
}
每次找到一个标记为PluginAttribute
的函数时,搜索一个具有与DefaultArguments
后缀相同的名称,没有参数且返回类型为object[]
的函数。然后调用它并将值存储在某个地方。您还应该支持使用专用的c#/VB语法指定的默认值(可以在参数的DefaultValue
成员中找到)
一种方法是为每个类设置属性Defaults
。它返回一个可以查询默认值的对象,例如:
object[] pluginFunctionDefaults = FooPlugin.Defaults["PluginFunction"];
(显然,您的应用程序中不会有这样的代码。)
默认值的声明可以像这样:
class FooPlugin
{
static FooPlugin()
{
var bar = new Bar();
Defaults = new DefaultValues()
.Add(() => PluginFunction(42, 13))
.Add(() => AnotherFunction(bar));
}
public static DefaultValues Defaults { get; private set; }
// actual methods of the class
}
使用这样的表达式意味着在编译时检查默认值的类型。DefaultValues
类解析表达式并存储参数。它可以看起来像这样:
class DefaultValues
{
private readonly Dictionary<string, object[]> m_expressions =
new Dictionary<string, object[]>();
public DefaultValues Add<T>(Expression<Func<T>> func)
{
var methodCall = ((MethodCallExpression)func.Body);
var name = methodCall.Method.Name;
var arguments =
methodCall.Arguments
.Select(Evaluate)
.ToArray();
m_expressions.Add(name, arguments);
return this;
}
private static object Evaluate(Expression expression)
{
return Expression.Lambda<Func<object>>(
Expression.Convert(expression, typeof(object)))
.Compile()();
}
public object[] this[string methodName]
{
get { return m_expressions[methodName]; }
}
}