2

这真的是一个两部分的问题。

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);

whereFunction1Array<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>这意味着没有直接的方法来以这种方式存储函数数组。

4

1 回答 1

2

您可以执行以下操作:

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为 use 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));
}
于 2013-05-16T21:10:38.683 回答