使用枚举值创建通用类型

4
我希望能够使用枚举值创建新的通用类型。我相信这在C++模板中是可能的,但我不知道是否可以在C#中实现。
所以我想做的是:
public class MyClass <T>
{
  public void Do<T>() {} 
}

public enum Metals
{
  Silver, Gold
}

我想传递一个枚举值,例如:

var myGoldClass = new MyClass<Metals.Gold>();

我想我可以创建名为Gold、Silver的类来实现这一点,但是我很喜欢使用枚举来限制我的泛型类的类型。
我之所以想在现实世界中使用这样的功能是因为我正在创建一个事件聚合器(发布-订阅模型),并且我希望我的订阅者订阅特定类型T的消息。因此,我认为如果我的订阅者可以使用枚举进行订阅,那就太好了。
编辑:为了澄清,Metals.Gold只是一个示例枚举。我希望客户端库能够创建自己的枚举/类,并将其用于订阅。我不会自己定义枚举。

2
不可能,因为枚举值不是一种类型。 - Matthew Watson
1
你需要添加一个参数:public void Do<T>(T item) {},并且可以这样使用它:MyClass<Metals>();myGoldClass.Do(Metals.Gold) - Ehsan Sajjad
我觉得我应该澄清一下我的前面的陈述:枚举值的类型就是枚举本身的类型。(虽然这对你也没有什么帮助。) - Matthew Watson
2
为什么不将枚举值作为构造函数参数传递? - Yacoub Massad
@EhsanSajjad - 麻烦在于我的订阅者,因为在那种情况下我将无法“定位”Message <T>类。尽管如此,这是一个好主意。 - arviman
显示剩余2条评论
2个回答

6

使用枚举值作为泛型参数是不可能的。在这种情况下,您应该使用继承:

public abstract class Metal
{
    protected Metals MetalType { get; private set; }

    protected Metal(Metals metal)
    {
        MetalType = metal;
    }
}

public class Gold : Metal
{
    public Gold() : base(Metals.Gold)
    {
    }
}

进一步地,有关PubSub实现的问题太过广泛,需要考虑很多方面。以下是一个例子,您可能会从中获取一些有用的想法:

public class EventHub
{
    // only one receiver per message type is allowed to simplify an example
    private static readonly ConcurrentDictionary<MessageTypes, IReceiver> receivers = 
        new ConcurrentDictionary<MessageTypes, IReceiver>();

    public bool TrySubscribe(MessageTypes messageType, IReceiver receiver)
    {
        return receivers.TryAdd(messageType, receiver);
    }

    public void Publish(IMessage message)
    {
        IReceiver receiver;

        if (receivers.TryGetValue(message.MessageType, out receiver))
        {
            receiver.Receive(message);
        }
    }
}

public interface IMessage
{
    MessageTypes MessageType { get; }
    string Text { get; set; }
}

public interface IReceiver
{
    void Receive(IMessage message);
}

谢谢你提供的发布-订阅部分,但我已经解决了这个问题。最终,我创建了一个基类作为我的事件聚合器中的约束,并使用该基类的派生类(例如您的Gold类)作为消息类型区分器。 - arviman

0

这是不可能的,因为T必须是一种类型而不是一个值。

也许我没有理解你的问题,但为什么不像这样做:

public class MyClass
{
    private readonly Metals _metal;

    public MyClass(Metals metal)
    {
        _metal = metal;
    }

    public void Do()
    {
        //using _metal here
    }
}

var myGoldClass = new MyClass(Metals.Gold);

我没有使用这条路线的原因是,当作为通用类型参数传递时,MyClass(Metals.Gold)与MyClass(Metals.Silver)相同。 - arviman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接