C# 如何实现可以接收任何参数并返回任何值的回调?
在c#中,我想设计一种模式,让用户注册回调:C# 如何实现可以接收任何参数并返回任何值的回调?,c#,oop,design-patterns,C#,Oop,Design Patterns,在c#中,我想设计一种模式,让用户注册回调: Pseudocode: RegisterCallBack(function, String key) 这样,我可以根据给定的键调用它运行时,如: callfunc(key) 然后可以调用该函数。我希望这个函数可以是任何接收任何参数并返回任何值的函数 那么,有谁能告诉我如何实现这一点吗?取决于您何时调用回调,您是希望返回什么,还是只是触发并忘记什么。如果只是开火然后忘记 RegisterCallback( Action<
Pseudocode:
RegisterCallBack(function, String key)
这样,我可以根据给定的键调用它运行时,如:
callfunc(key)
然后可以调用该函数。我希望这个函数可以是任何接收任何参数并返回任何值的函数
那么,有谁能告诉我如何实现这一点吗?取决于您何时调用回调,您是希望返回什么,还是只是触发并忘记什么。如果只是开火然后忘记
RegisterCallback( Action<String> callback, String key) { ... }
然后将其称为回调(键)代码>。但是在注册回调时,客户机代码需要如下所示
void myCallBack(String[] keys){ ... }
foo.RegisterCallback(myCallBack, "bar", "baz");
请注意,myCallBack
实现没有正确命名的参数。我无法以任何方式在回调实现中同时拥有命名参数和任意数量的参数。因为任何委托都可以被强制转换为委托
,所以没有什么可以阻止这样做:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public class CallbackArgs1
{
public CallbackArgs1(string text)
{
Text = text;
}
public string Text { get; }
}
public class CallbackArgs2
{
public CallbackArgs2(int number)
{
Number = number;
}
public int Number { get; }
}
public static void Main()
{
// #1 You build a callback list with two sample callbacks
List<Delegate> callbacks = new List<Delegate>();
callbacks.Add(new Func<CallbackArgs1, int>(args => args.Text.Length));
callbacks.Add(new Func<CallbackArgs2, string>(args => args.Number.ToString()));
// This list will store each callback result
List<object> callbackResults = new List<object>();
foreach(Delegate callback in callbacks)
{
// #2 This gets first Func<T, TResult> generic argument
// which is the argument class type
Type argsType = callback.GetType().GetGenericArguments()[0];
// #3 Now it's about checking the arguments class type
// and instantiate it
object args;
if(typeof(CallbackArgs1).IsAssignableFrom(argsType))
{
args = new CallbackArgs1("hello world");
}
else if(typeof(CallbackArgs2).IsAssignableFrom(argsType))
{
args = new CallbackArgs2(282);
}
else
{
throw new NotSupportedException();
}
// #4 Finally, the callback is dynamically called passing
// the arguments class instance and the return value is
// stored in the callback result list.
callbackResults.Add(callback.DynamicInvoke(new [] { args }));
}
Console.WriteLine(string.Join(", ", callbackResults.Select(r => r.ToString())));
}
}
使用系统;
使用System.Linq;
使用System.Collections.Generic;
公共课程
{
公共类回调args1
{
公共回调args1(字符串文本)
{
文本=文本;
}
公共字符串文本{get;}
}
公共类回调args2
{
公共回拨args2(整数)
{
数字=数字;
}
公共整数{get;}
}
公共静态void Main()
{
//#1您构建了一个包含两个示例回调的回调列表
列表回调=新列表();
Add(newfunc(args=>args.Text.Length));
Add(newfunc(args=>args.Number.ToString());
//此列表将存储每个回调结果
List callbackResults=new List();
foreach(回调中的委托回调)
{
//#2这将获得第一个Func泛型参数
//哪个是参数类类型
类型argsType=callback.GetType().GetGenericArguments()[0];
//#3现在要检查参数类类型
//并将其实例化
对象args;
if(typeof(CallbackArgs1).IsAssignableFrom(argsType))
{
args=newcallbackargs1(“你好世界”);
}
else if(typeof(CallbackArgs2).IsAssignableFrom(argsType))
{
args=新回拨args2(282);
}
其他的
{
抛出新的NotSupportedException();
}
//#4最后,回调被动态地称为传递
//参数类实例和返回值为
//存储在回调结果列表中。
callbackResults.Add(callback.DynamicInvoke(new[]{args}));
}
WriteLine(string.Join(“,”,callbackResults.Select(r=>r.ToString()));
}
}
也就是说,您可以构建一个具体委托的回调列表,这些委托被强制转换为Delegate
,并动态地调用它们,传递正确的参数检查第一个Func
参数类型
因此,惯例是必须使用Func
,其中T
将是一类与代码段中的参数类似的参数,TResult
可以是任何类型,无论是引用类型还是值类型
无论如何,我不确定这是否适用于您,因为您需要以某种方式来决定为特定参数类提供哪些参数,而不是我在代码段中的做法,我在代码段中对它们进行了硬编码…如果您开始使用callfunc(key)
调用它,参数将从何而来?返回值将返回到哪里?作为callfunc
的返回值,Params-使用Func查找参数数量有限
void myCallBack(String[] keys){ ... }
foo.RegisterCallback(myCallBack, "bar", "baz");
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public class CallbackArgs1
{
public CallbackArgs1(string text)
{
Text = text;
}
public string Text { get; }
}
public class CallbackArgs2
{
public CallbackArgs2(int number)
{
Number = number;
}
public int Number { get; }
}
public static void Main()
{
// #1 You build a callback list with two sample callbacks
List<Delegate> callbacks = new List<Delegate>();
callbacks.Add(new Func<CallbackArgs1, int>(args => args.Text.Length));
callbacks.Add(new Func<CallbackArgs2, string>(args => args.Number.ToString()));
// This list will store each callback result
List<object> callbackResults = new List<object>();
foreach(Delegate callback in callbacks)
{
// #2 This gets first Func<T, TResult> generic argument
// which is the argument class type
Type argsType = callback.GetType().GetGenericArguments()[0];
// #3 Now it's about checking the arguments class type
// and instantiate it
object args;
if(typeof(CallbackArgs1).IsAssignableFrom(argsType))
{
args = new CallbackArgs1("hello world");
}
else if(typeof(CallbackArgs2).IsAssignableFrom(argsType))
{
args = new CallbackArgs2(282);
}
else
{
throw new NotSupportedException();
}
// #4 Finally, the callback is dynamically called passing
// the arguments class instance and the return value is
// stored in the callback result list.
callbackResults.Add(callback.DynamicInvoke(new [] { args }));
}
Console.WriteLine(string.Join(", ", callbackResults.Select(r => r.ToString())));
}
}