1

C# 相关 - 是否有比“打开类型”更好的替代方法?

我需要“打开类型”:给定一个 type 的参数T,找到并执行一个 form 的方法void Method (T param)

这可以通过 switch 语句或 a 来解决Dictionary<Type, Action>,但是我想避免在这种情况下进行必要的强制转换。

我找不到上述(或类似)问题中提到的以下方法:

  1. 创建一个充当集合的静态泛型类型:

    public static class Commands<T> {
      public static Action<T> Handler;
    }
    
  2. 创建一个使用该类型的存储库,如类型安全字典:

    public class CommandRepository {
        public void Register<T>(Action<T> handler) {
            Commands<T>.Handler = handler;
        }
    
        public void Run<T>(T parameter) {
            // null checks etc.
            Commands<T>.Handler(parameter);
        }
    }
    
  3. 示例用法:

    public void CreateUser(CreateUserParams p) {
        Console.WriteLine("Creating " + p.Name);
    }
    
    // ...
    var repo = new CommandRepository();
    
    repo.Register<CreateUserParams>(CreateUser);
    repo.Register<DeleteUserParams>(DeleteUser);
    
    repo.Run(new CreateUserParams { Name = "test" });
    repo.Run(new DeleteUserParams { Name = "test" });
    

如前所述,使用Dictionary<Type, Action>中的a 可以实现相同的行为ComandRepository,但是我必须转换方法参数,或者,如果我使用接口而不是Action,则IFoo<T>在获取字典项后转换为 a 。

我的问题是:可以(ab-)使用这样的泛型类型(给定大量可能的值T)吗?

(奖励问题)如果不行,为什么不呢?这会导致什么成本/负面影响?

最后一点:我意识到这不适用于类型层次结构或接口。类型T必须完全匹配,这在我的场景中很好。

编辑:我发现Jil,一个 JSON 序列化器,也依赖于这种模式。查看TypeCache类型,它存储了一个委托来序列化一个类型的对象T(据我通过浏览代码了解到的)。由于这TypeCache将存储大量类型,我认为该模式通常没有问题。

了解类型或其静态成员是否需要进行垃圾收集,或者是否需要考虑其他性能影响仍然很有趣。

4

2 回答 2

1

您建议的方法是可行的,但缺点是您的存储库实际上是一个单例。如果您发现自己需要一个不像单例的存储库,您可能会发现ConditionalWeakTable[1] 类型很有帮助。使用其中一个的技巧是,对于每种感兴趣的类型,您都会有一个单例ConditionalWeakTable,它将您的对象映射到与该类型关联的事物(如果有的话)。该类仅在 .NET 4.0 中可用,但可以做一些很棒的事情。

[1] http://msdn.microsoft.com/en-us/library/dd287757.aspx

例如,假设有人想要一种OutTypeKeyedDictionary支持 aSetValue<T>(T Value)和的类型bool TryGetValue<T>(out T Value)。可以使用一个静态类族OutputMappers<T>,其中每个类都拥有一个ConditionalWeakTable<OutTypeKeyedDictionary, T>. OutTypeKeyedDictionary实际上不会有任何字段(!);相反,每个实例都将纯粹用作身份令牌,该身份令牌将用作ConditionalWeakTable密钥。顺便说一句,类在CompilerServices命名空间中的原因Collections是它被ExpandoObject.

于 2013-08-27T16:11:00.000 回答
-1

使用仅提供单次调度的 C# 等语言实现双重调度的常用方法是访问者模式。您的示例如下所示:

接口:

interface IVisitor
{
    void VisitCreateUserParams(CreateUserParams p);

    void VisitDeleteUserParams(DeleteUserParams p);
}

interface IParams
{
    void Accept(IVisitor visitor);
}

命令参数:

class CreateUserParams : IParams
{
    public void Accept(IVisitor visitor) { visitor.VisitCreateUserParams(this); }

    public string Name { get; set; }
}

class DeleteUserParams : IParams
{
    public void Accept(IVisitor visitor) { visitor.VisitDeleteUserParams(this); }

    public string Name { get; set; }
}

命令:

class CommandHandler : IVisitor
{
    public void VisitCreateUserParams(CreateUserParams p)
    {
        Console.WriteLine("Creating " + p.Name);
    }

    public void VisitDeleteUserParams(DeleteUserParams p)
    {
        Console.WriteLine("Deleting " + p.Name);
    }
}

示例用法:

var handler = new CommandHandler();

new CreateUserParams { Name = "test" }.Accept(handler);
new DeleteUserParams { Name = "test" }.Accept(handler);
于 2013-08-27T14:12:22.620 回答