Enum 类型的通用签名

发布于 2024-11-03 07:40:08 字数 2550 浏览 0 评论 0原文

我在我的项目中定义了几种 Enum 类型,用于特定于对象的状态标识符:

  public enum ObjectAState
  {
    ObjectAAvailable,
    ObjectADeleteRequested,
    ObjectADeleted
  }
  public enum ObjectBState
  {
    ObjectBCreationRequested,
    ObjectBCreationFailed,
    ObjectBDeleteRequested,
    ObjectBDeleted
  }

任何使用 ObjectA 的人只能引用 ObjectA 枚举,所有其他对象也是如此 - 它们的枚举是隔离的,这使得它们更容易理解,因为不显示不适用于对象的状态(这就是为什么我不只是将所有对象的所有状态放在一个枚举中)。

对于给定的状态,可以有零个、一个或多个其他状态(在同一个enum内);根据定义,也有某些国家无法遵循。例如,在 ObjectA 中,状态可以从 ObjectAAvailable 转换到 ObjectADeleteRequested,以及从 ObjectADeleteRequested 转换到 ObjectADeleted,但不是直接从 ObjectAAvailableObjectADeleted。在每个对象中都有一些乏味且重复的代码来强制执行有效的状态转换,我想用一个方法来替换它们。

作为测试,我这样做了:

Dictionary<ObjectAState, List<ObjectAState>> Changes = new Dictionary<ObjectAState, List<ObjectAState>>();

这是一个通过 ObjectAState 作为键访问的 Dictionary,包含其他 ObjectAState< 的 List /code> 值表示有效的转换,如下所示:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });
Changes.Add(ObjectAState.ObjectAADeleteRequested, new List<ObjectAState> { ObjectAState.ObjectADeleted });
Changes.Add(ObjectAState.ObjectADeleted, null);

我有一个方法,看起来像这样:

public bool StateTransitionIsValid(ObjectAState currentState, ObjectAState targetState)
{
  return Changes[currentState].Contains(targetState);
}

这完美地工作 - ObjectA 的用户只需传入对象当前和目标状态的 enum并得到一个简单的 true 或 false 来判断转换是否是 有效的。那么,如何使这个通用,以便相同的方法可以处理来自其他对象的枚举?

我尝试了这个:

Dictionary<Enum, List<Enum>> Changes = new Dictionary<Enum, List<Enum>>();

它编译时没有错误 - 但是向字典添加条目的代码失败了:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });

Error   1   The best overloaded method match for 'System.Collections.Generic.Dictionary<System.Enum,System.Collections.Generic.List<System.Enum>>.Add(System.Enum, System.Collections.Generic.List<System.Enum>)' has some invalid arguments
Error   2   Argument 2: cannot convert from 'System.Collections.Generic.List<MyApp.ObjectAState>' to 'System.Collections.Generic.List<System.Enum>'

我四处寻找,似乎看不出我做错了什么。有人知道为什么我的“通用”版本无法编译吗?

I have several Enum types defined across my project, used for object-specific state identifiers:

  public enum ObjectAState
  {
    ObjectAAvailable,
    ObjectADeleteRequested,
    ObjectADeleted
  }
  public enum ObjectBState
  {
    ObjectBCreationRequested,
    ObjectBCreationFailed,
    ObjectBDeleteRequested,
    ObjectBDeleted
  }

Anyone using ObjectA can only refer to ObjectA enums, and the same is true of all the other objects - their enums are isolated, and this makes them easier to understand since states which are not applicable to an object are not shown (this is why I don't just put all the states for all objects in a single enum).

For a given state, there are zero, one or many other states (within the same enum) which can follow; by definition, there are also certain states which cannot follow. In ObjectA, for example, the state can transition from ObjectAAvailable to ObjectADeleteRequested, and from ObjectADeleteRequested to ObjectADeleted, but not directly from ObjectAAvailable to ObjectADeleted. In each object there is a tedious and repetitive bit of code to enforce valid state transitions, which I want to replace with a single method.

As a test, I did this:

Dictionary<ObjectAState, List<ObjectAState>> Changes = new Dictionary<ObjectAState, List<ObjectAState>>();

This is a Dictionary accessed via ObjectAState as a key, holding a List of other ObjectAState values which indicate valid transitions populated thus:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });
Changes.Add(ObjectAState.ObjectAADeleteRequested, new List<ObjectAState> { ObjectAState.ObjectADeleted });
Changes.Add(ObjectAState.ObjectADeleted, null);

And I have a method which simply looks like this:

public bool StateTransitionIsValid(ObjectAState currentState, ObjectAState targetState)
{
  return Changes[currentState].Contains(targetState);
}

This works perfectly - users of ObjectA simply pass in the enum of the current and target states of the object and get a simple true or false for whether the transition is valid. So, how to make this generic so that the same method can handle enums from other objects?

I tried this:

Dictionary<Enum, List<Enum>> Changes = new Dictionary<Enum, List<Enum>>();

It compiles without error - but the code which adds entries to the Dictionary fails:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested });

Error   1   The best overloaded method match for 'System.Collections.Generic.Dictionary<System.Enum,System.Collections.Generic.List<System.Enum>>.Add(System.Enum, System.Collections.Generic.List<System.Enum>)' has some invalid arguments
Error   2   Argument 2: cannot convert from 'System.Collections.Generic.List<MyApp.ObjectAState>' to 'System.Collections.Generic.List<System.Enum>'

I've had a hunt around and can't seem to see what I'm doing wrong. Anyone got any ideas why my 'generic' version doesn't compile?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倾`听者〃 2024-11-10 07:40:08

您的方法或类必须是通用定义的,以便您可以使用实际的通用类型。

困难在于没有办法在编译时完全强制泛型类型是 Enum。这可能是您最接近的:

public class MyTestClass<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        if(!typeof (T).IsEnum) 
            throw new Exception(typeof(T).FullName + " is not an enum type.");
    }

    Dictionary<T, List<T>> Changes = new Dictionary<T, List<T>>();
    ...
}

Your method or class must be generically defined, so that you have an actual generic type to work with.

The difficulty is that there is no way to fully enforce that the generic type is an Enum at compile time. This is probably the closest you'll come:

public class MyTestClass<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        if(!typeof (T).IsEnum) 
            throw new Exception(typeof(T).FullName + " is not an enum type.");
    }

    Dictionary<T, List<T>> Changes = new Dictionary<T, List<T>>();
    ...
}
丢了幸福的猪 2024-11-10 07:40:08

我认为这是因为您尝试使用非通用对象,尽管定义是通用的。试试这个。

Changes.Add(ObjectAState.ObjectAAvailable, new List<Enum> { ObjectAState.ObjectADeleteRequested });

I think it's because you are trying to use a non generic object although the definition was generic. try this.

Changes.Add(ObjectAState.ObjectAAvailable, new List<Enum> { ObjectAState.ObjectADeleteRequested });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文