是否可以将此类转换为通用类?

时间:2011-08-30 08:59:15

标签: c# generics delegates

是否有人能够“概括”此问题底部列出的类?我希望该类不被锁定为“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;
    }
}

3 个答案:

答案 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>();