这实际上是一个由两部分组成的问题。
<强>1。如何将参数不同类型的函数数组存储在 Array 或 IEnumerable 中
是否可以编写如下代码:
Func<object, bool> fObj = (o) => false;
Func<Animal, bool> fAni = (a) => false;
Func<Cat, bool> fCat = (c) => true;
var funcArray = new Function1Array<bool>(fObj, fAni, fCat);
哪里Function1Array<T>
需要类似 (params Func<?, T>[] funcs)
,即使 c# 不允许通用通配符
<强>2。假设问题 1 可以完成,是否可以检查一个对象是否与其中一个函数的参数类型相同,如果是,则强制转换为该对象
示例:
Cat myCat = new Cat();
funcArray.invokeFirstMatch(myCat); // Invokes fCat(myCat)
object myCat2 = new Cat(); // Declared as object instead of Cat
funcArray.invokeFirstMatch(myCat2); // Invokes fCat(myCat2)
Dog myDog = new Dog();
funcArray.invokeFirstMatch(myDog); // Invokes fObj(myDog)
我的猜测是,如果不以某种方式包装每个函数,这两个问题都是不可能的,因为 Func<Cat, bool>
不是 Func<object, bool>
的子类型这意味着没有直接的方法来以这种方式存储函数数组。
最佳答案
你可以这样做:
public class Function1Array<TOut> : IEnumerable
{
private readonly List<Delegate> funcs = new List<Delegate>();
public void Add<T>(Func<T, TOut> f)
{
this.funcs.Add(f);
}
public TOut InvokeFirstMatch<T>(T arg)
{
Delegate first = this.funcs.FirstOrDefault(d => d.GetType().GetGenericArguments()[0] == typeof(T));
if (first == null) throw new ArgumentException("No match");
return ((Func<T, TOut>)first)(arg);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.funcs.GetEnumerator();
}
}
您可以使用集合初始化程序对其进行初始化:
var arr = new Function1Array<bool> { fObj, fAni, fCat };
请注意,这需要参数类型完全匹配,尽管您可以更改为 FirstOrDefault
指定的谓词以使用 IsAssignableFrom
。
InvokeFirstMatch
的泛型参数意味着搜索是根据参数的静态类型完成的。您可以改用运行时类型:
public TOut InvokeFirstMatch(object arg)
{
var argType = arg.GetType();
Delegate first = this.funcs.FirstOrDefault(d => d.GetType().GetGenericArguments()[0] == argType);
if (first == null) throw new ArgumentException("No match");
return (TOut)first.DynamicInvoke(Convert.ChangeType(arg, argType));
}
关于arrays - c# 单参数函数数组,每个函数具有不同类型的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16597185/