是否有可能把这个类变成一个泛型类

本文关键字:泛型类 一个 有可能 是否 | 更新日期: 2023-09-27 18:07:05

有人能概括出这个问题底部列出的类别吗?我希望类不被锁定到类型为"GetStateDelegate"的委托,而是一个通用委托。这可能吗?

我已经尝试了一些事情,但是1)c#不喜欢这种类型的类声明:

public class StringToMethodMapper<T> where T: System.Delegate

这会产生"Cannot use System. "委托为类型参数约束"

如果你能给我一些提示,让我走上正轨,我会很感激的。此外,如果存在解决方案,我希望消费者尽可能少地受到更改的影响。例如,我宁愿不改变"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;
    }
}

是否有可能把这个类变成一个泛型类

在通用方面…嗯,这是有可能的。我有一个名为Unconstrained Melody的库,它使用IL重写具有委托约束的泛型-您可以在代码中使用相同的IL重写器。不过它很丑。基本上IL支持你想要的约束,但是c#不支持。请注意,没有可能的约束"它应该是一个从MulticastDelegate派生但不包括MulticastDelegate本身的类型"…所以有人可以创建一个StringToMethodMapper<MulticastDelegate>,但这是不太可能的。

如果你愿意坚持使用一种类型的委托签名(例如:"总是三个参数和一个void返回"),那么您可以使用George的答案中的方法。如果它应该用于任何委托类型,那么您将坚持使用IL重写方法或放弃约束。


(根据评论编辑)

对于剩下的代码来说,这是对字典的一个非常缓慢的使用。目前你需要O(n)次查找。只需通过TryGetValue使用正常的Dictionary访问,但将StringComparer.OrdinalIgnoreCase(或类似的东西)传递到构造函数中以获得不区分大小写的匹配。不可否认,这不会是一场比赛的开始……但是您当前的方法无论如何都不是确定的,因为您可能最终以"foo"answers"fo"作为字典中的键,它们都将匹配-因此您依赖于迭代器返回键的顺序。不是个好主意。

如果你真的需要StartsWith行为,你可能想要调查实现一个trie -或者如果你对O(N)查找感到满意,我会保留一个List<KeyValuePair<string, TDelegate>>,以明确你并没有真正使用它作为字典。

可能如下所示(键入时没有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;
    }
}

一种方法是将委托替换为接口

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