除了第一个参数的类型之外,我有一堆静态方法都具有相同的签名,例如:
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都可用于此.
正如评论所涵盖的那样,并非如此.但是我认为你可以建立一个完成你想要的课程(相对类型安全,使用愉快).
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)
我不认为你会在调用时支付除了演员之外的任何东西,但是没有描述确认.
| 归档时间: |
|
| 查看次数: |
326 次 |
| 最近记录: |