我可以创建一个Funcs字典,它们的第一个参数有所不同吗?

Mic*_*tum 2 .net c#

除了第一个参数的类型之外,我有一堆静态方法都具有相同的签名,例如:

public static class ElementCreators
{
    public static XmlElement CreateElementForString
               (string s, string name, string namespaceURI)
    {
        [...]
    }

    public static XmlElement CreateElementForDecimal
               (Decimal d, string name, string namespaceURI)
    {
        [...]
    }
}
Run Code Online (Sandbox Code Playgroud)

我想创建一个Dictionary(或某种可以在运行时修改的查找 - 人们应该能够添加自己的func,但是一旦添加了func,就不需要修改/删除它,并且对于给定类型,永远不会有两个+ func.可能有基本和派生类型的函数,但在这种情况下,由用户注册它们,例如,按照正确的顺序)根据类型进行调度,例如:

var funcs = new Dictionary<Type, Func<object, string, string, XmlElement>>();
funcs[typeof(string)] = ElementCreators.CreateElementForString;
funcs[typeof(Decimal)] = ElementCreators.CreateElementForDecimal;
Run Code Online (Sandbox Code Playgroud)

现在,这不起作用,因为代理之间没有相反的变化,所以编译器抱怨这一点CS0123 No overload for 'CreateElementForString' matches delegate 'Func<object, string, string, XmlElement>'.

一种选择是创建另一个委托作为中间人:

funcs[typeof(string)] =
            (o,s1,s2) => ElementCreators.CreateElementForString((string)o, s1, s2);
Run Code Online (Sandbox Code Playgroud)

这是有效的,但是a)丑陋和b)介绍了一堆不必要的代表.

泛型似乎不是一个选项,因为Func不能是开放类型T.同样,动态不起作用,但我不想使用这些(运行时成本).

我可以为每个方法引入一个间接级别,这避免了委托,但它并没有那么难看:

public static XmlElement CreateElementForString(object s, string name, string namespaceURI)
    => CreateElementForString((string)s, name, namespaceURI);
Run Code Online (Sandbox Code Playgroud)

当然,我可以尝试自动化类似的东西(T4模板,预构建任务,自定义构建操作等)

但在我这样做之前,我想知道是否有更好的方式让我忽略了?

Visual Studio 2017,.NET 4.7.1和C#7.2都可用于此.

Kev*_*ose 5

正如评论所涵盖的那样,并非如此.但是我认为你可以建立一个完成你想要的课程(相对类型安全,使用愉快).

public class DelegateDictionary
{
    Dictionary<Type, Delegate> Lookup;

    public DelegateDictionary()
    {
        Lookup = new Dictionary<System.Type, Delegate>();
    }

    public void Add<T>(Func<T, string, string, XmlElement> mtd)
    {
        Lookup.Add(typeof(T), mtd);
    }

    public XmlElement Invoke<T>(T value, string name, string namespaceURI)
    {
        if (!Lookup.TryGetValue(typeof(T), out var del)) throw new InvalidOperationException($"No delegate registered for {typeof(T).Name}");

        var typedDel = (Func<T, string, string, XmlElement>)del;
        return typedDel(value, name, namespaceURI);
    }
}
Run Code Online (Sandbox Code Playgroud)

你必须键入Add(...)调用,它不能被推断),但Invoke(...)可以推断(并且可能有更多的调用而不是注册).

// example usage
{
    var dict = new DelegateDictionary();

    dict.Add<string>(ElementCreators.CreateElementForString);
    dict.Add<Decimal>(ElementCreators.CreateElementForDecimal);

    dict.Invoke("stringValue", "myName", "what-even-is-a-namespace");
    dict.Invoke(1.0m, "myName", "what-even-is-a-namespace");
}
Run Code Online (Sandbox Code Playgroud)

我不认为你会在调用时支付除了演员之外的任何东西,但是没有描述确认.