简体   繁体   English

参数化通用接口 - 创建字典 <Type, Interface<T> &gt;?

[英]Parameterize a generic interface - Create a Dictionary<Type, Interface<T>>?

Sorry the title is confusing, I don't know if I said it right, not sure what this thing is called... Feel free to edit it after you read the question if you want. 对不起,标题令人困惑,我不知道我说的是对的,不知道这个叫什么东西......如果你想要的话,请在阅读问题后随意编辑。

I'm refactoring my old code when I noticed there are a lot of places where I could use the Strategy pattern. 当我注意到有很多地方可以使用策略模式时,我正在重构我的旧代码。 I have an inventory system, and items - There are more than one ways to add an item - Normal way, forceful way, etc. You could also swap items, again, with more than one way - So I figured those are good places to use that pattern. 我有一个库存系统和物品 - 有多种方法可以添加物品 - 正常方式,有力的方式等等。您还可以使用多种方式再次交换物品 - 所以我认为这些是很好的地方使用那种模式。

Here is what I have, for adding items: 这是我有的,用于添加项目:

public interface IAddingStrategy<T> where T : AddArgs
{
    bool Add(T args);
}

public class NormalAdd : IAddingStrategy<NormalAddArgs>
{
    public bool Add(NormalAddArgs args)
    {
        // normal adding logic...
    }
}

public class ForceAdd : IAddingStrategy<ForceAddArgs>
{
    public bool Add(ForceAddArgs args)
    {
        // force adding logic...
    }
}

// other strategies...

public abstract class AddArgs
{
}

public class NormalAddArgs : AddArgs
{
    public readonly param1 p1;
    public readonly param2 p2;
    etc;

    public NormalAddArgs(param1 p1, param2 p2, etc)
    {
        this.p1 = p1;
        this.p2 = p2;
        this.etc = etc;
    }
}

public class ForceAddArgs : AddArgs
{
    public param3 p3;

    public ForceAddArgs(param3 p3)
    {
        this.p3 = p3;
    }
}

// other adding args...

Now what I'm trying to do - But don't know how to, is: 现在我正在尝试做什么 - 但不知道该怎么做,是:

public class Adder
{
    private Dictionary<Type, SOMETHING> dic = new Dictionary<Type, SOMETHING>();
    public Adder()
    {
        dic.Add(typeof(NormalAdd), new NormalAdd());
        dic.Add(typeof(ForceAdd), new ForceAdd());
        dic.Add(typeof(EtcAdd), new EtcAdd());
    }
}

What should SOMETHING be? 我应该SOMETHING是什么? I want it to be any adding strategy - But if I go for IAddingStrategy - it doesn't work since it requires me to specify the <T> parameter which if I do, the dictionary can't hold all the possible types of strategies... ;( 我希望它是任何添加策略 - 但如果我去IAddingStrategy - 它不起作用,因为它要求我指定<T>参数,如果我这样做,字典不能保存所有可能类型的策略。 ..;(

Any ideas how to go about this? 任何想法如何去做? what should SOMETHING be? 应该什么SOMETHING是什么? Am I right of using the strategy pattern in this situation? 在这种情况下,我是否正确使用策略模式? If not, what's the best approach to this? 如果没有,最好的办法是什么?

Thanks all for your help. 感谢你的帮助。

EDIT: One way around this, would be something like this: 编辑:解决这个问题的方法是这样的:

public interface IAddingStrategy
{
    void Add(AddArgs args);
}

public class NormalAdd: IAddingStrategy
{
    public void Add(AddArgs args)
    {
        if (args is NormalAddArgs)
            // normal add logic
    }
}

public class ForceAdd: IAddingStrategy
{
    public void Add(AddArgs args)
    {
        if (args is ForceAddArgs)
            // force add logic
    }
}

Then the dictionary would simply be <Type, IAddingStrategy> 然后字典就是<Type, IAddingStrategy>

But really, I don't like the if thing, it just doesn't feel right - what if someone passes the wrong type of arg? 但实际上,我不喜欢if东西,它只是感觉不对 - 如果有人通过了错误类型的arg怎么办? that is something only detected at run-time, I want to detect the thing at compile-time. 这是在运行时才检测到的东西,我想在编译时检测到这个东西。 - Using generics I was able to achieve that. - 使用泛型我能够实现这一点。

Per my comments: it may make sense to minimize the exposure of the generic interface, rather than requiring generic arguments to the chain of callers. 根据我的评论:最小化通用接口的暴露可能是有意义的,而不是要求调用者链的泛型参数。 One way to do this is to implement both a generic and non-generic interface. 一种方法是实现通用和非通用接口。

PROS: 优点:

  • You can now work with a non-generic interface. 您现在可以使用非通用接口。
  • Reasonable type safety (in most cases). 合理的类型安全(大多数情况下)。

CONS: 缺点:

  • Casts are required. 演员是必需的。
  • Every method needs two implementations. 每个方法都需要两个实现。
  • Type safety isn't guaranteed by the compiler. 编译器无法保证类型安全。
/// <summary>Some common base type.</summary>
public interface IAddArgs {}

/// <summary>Non-generic interface.</summary>
public interface IAddingStrategy
{
    void Add( IAddArgs obj );
}

/// <summary>Generic version.</summary>
/// <typeparam name="T"></typeparam>
public interface IAddingStrategy<T> : IAddingStrategy
    where T : IAddArgs
{
    void Add( T obj );
}

public class NormalAddArgs : IAddArgs {}

public class NormalAdd : IAddingStrategy<NormalAddArgs>
{
    public void Add( NormalAddArgs obj )
    {

    }

    public void Add( IAddArgs obj )
    {
        Add( (NormalAddArgs)obj );
    }
}

This does leave the nagging problem of how to create the correct type of arguments in the first place, ie what class has enough information to create an instance of NormalAddArgs so that it can be passed to the appropriate strategy? 这确实留下了如何创建正确类型的参数的唠叨问题,即哪个类有足够的信息来创建NormalAddArgs的实例,以便它可以传递给适当的策略?

One way is to ask each type to create these types for you: 一种方法是要求每种类型为您创建这些类型:

/// <summary>Non-generic interface.</summary>
public interface IAddingStrategy
{
    void Add( IAddArgs obj );

    // "context" can be a type that provides additional info
    IAddArgs CreateAddArgs( object context );
}

public class NormalAdd : IAddingStrategy<NormalAddArgs>
{
    public void Add( NormalAddArgs obj ) { }

    public void Add( IAddArgs obj )
    {
        Add( (NormalAddArgs)obj );
    }

    public IAddArgs CreateAddArgs( object context )
    {
        return new NormalAddArgs();
    }
}

I don't think you are going to be able to have a Dictionary<Type, Interface<T>> in your case since you would need to define T to be common to all values in the dictionary. 我认为你不能在你的情况下有一个Dictionary<Type, Interface<T>> ,因为你需要定义T对于字典中的所有值都是通用的。

Jon Skeet gives an excellent answer to a similar question: Generic Dictionary with a value as a Interface with a Generic reference . Jon Skeet给出了一个类似问题的优秀答案: 通用字典,其值为带有通用引用的接口 I hope it helps you too. 我希望它对你也有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM