是否有人能够“概括”此问题底部列出的类?我希望该类不被锁定为“GetStateDelegate”类型的委托,而是一般代理。那可能吗?
我尝试了几件事,但1)C#不喜欢这种类声明:
public class StringToMethodMapper<T> where T: System.Delegate
这会产生“不能将System.Delegate用作类型参数约束”
感谢让我走上正确的道路。此外,如果存在解决方案,我希望消费者尽可能不受更改的影响。例如,我宁愿不更改“Add(string,delegate)”的调用代码。
代码:
public delegate bool GetStateDelegate(object someObject);
public class StringToMethodMapper
{
private Dictionary<string, GetStateDelegate> _methods;
public StringToMethodMapper()
{
_methods = new Dictionary<string, GetStateDelegate>();
}
public void Add(string key, GetStateDelegate method)
{
_methods.Add(key, method);
}
internal virtual GetStateDelegate GetMethodFor(string key)
{
foreach (var storedKey in _methods.Keys)
{
if (key.ToUpper().StartsWith(storedKey.ToUpper()))
{
return _methods[storedKey];
}
}
return null;
}
}
答案 0 :(得分:1)
下面的内容,也许(没有IDE输入)。显然客户端需要添加通用参数,但我认为添加的调用仍然有效。
public class StringToMethodMapper<T, TResult>
{
private Dictionary<string, Func<T, TResult>> _methods;
public StringToMethodMapper()
{
_methods = new Dictionary<string, Func<T, TResult>>();
}
public void Add(string key, Func<T, TResult> method)
{
_methods.Add(key, method);
}
internal virtual Func<T, TResult> GetMethodFor(string key)
{
foreach (var storedKey in _methods.Keys)
{
if (key.ToUpper().StartsWith(storedKey.ToUpper()))
{
return _methods[storedKey];
}
}
return null;
}
}
答案 1 :(得分:1)
在使它成为通用的方面......好吧,它有点可能。我有一个名为Unconstrained Melody的库,它使用IL重写代理约束的泛型 - 你可以在代码中使用相同的IL重写器。虽然它很丑陋。基本上IL支持您想要的约束,但C#不支持。请注意,“它应该是从MulticastDelegate
派生的类型,但不包括MulticastDelegate
本身”,因此没有可能的约束“......所以某人可以创建StringToMethodMapper<MulticastDelegate>
但那非常不合时宜。
如果你很乐意坚持代理签名的一个种(例如“总是三个参数和一个无效的返回”),那么你可以使用乔治答案的方法。如果它应该是任何委托类型,那么你就会陷入IL重写方法或放弃约束。
(根据评论编辑。)
就其余代码而言,这是一个非常慢的字典使用。目前你有O(n)查找。只需通过Dictionary
使用普通TryGetValue
访问权限,但将StringComparer.OrdinalIgnoreCase
(或类似内容)传递到构造函数中以获得不区分大小写的匹配。那不会得到一个开始匹配,诚然......但是你当前的方法无论如何都不是确定性的,因为你最终可以将“foo”和“fo”作为字典中的键,两者都匹配 - 所以你依赖于迭代器返回键的顺序。不是一个好主意。
如果您确实需要StartsWith
行为,可能需要调查实施trie - 或者如果您对O(N)查找感到满意,我会保留List<KeyValuePair<string, TDelegate>>
明确表示你并没有真正将它用作字典。
答案 2 :(得分:0)
执行此操作的一种方法是将代理交换为接口
public interface IGetState
{
bool GetState(object someObject);
}
然后您可以使用此界面作为约束
public class StringToMethodMapper<T> where T: IGetState
{
...
}
然后,您可以实现界面以创建特定内容,例如:
public class FileSystemState : IGetState
{
public bool GetState(object someObject)
{
// get state from the FS
}
}
然后
var fileSystemMapper = new StringToMethodMapper<FileSystemState>();