是否有一个解决方法的一般类型约束的"特别类"Enum在C#3.0?[重复]
-
05-07-2019 - |
题
这个问题已经有一个答案在这里:
更新: 看看底下的这个问题对于C#解决方法。
嗨,
考虑下列扩展的方法:
public static bool HasFlags<T>(this T value, T flags)
where T : System.Enum
{
// ...
}
这将作为你可能知道,扔一个错误是在编写时,由于一类,通常不允许继承 System.Enum
.问题是,任何列举指定的使用 enum
关键词实际上会继承 System.Enum
, 因此上述码会是理想的方式限制一个扩展方法,以枚举的只。
现在显而易见的工作-在这里是使用 Enum
而不是的 T
, 但然后你失去的惠益的一般类型:
MyEnum e;
e.HasFlags(MyOtherEnum.DoFunkyStuff);
上述代码扔一个编译时间的错误使用通用类型,而它只能引发运行时使用错误 Enum
类型(如果我实现它这样做。)
是否有任何编译器的选择,可以用来关闭的约束检查,或是有其他一些漂亮的方式做到这一点?
在它之前的建议,我想说,我将不使用 where T : struct
或一些这样的,因为然后你可以做奇怪的东西喜欢 123.HasFlags(456)
.
我难住了,为什么这一存在错误。这是同样的问题,你会得到使用 where T : System.Object
, 但你有 where T : class
...为什么没有 where T : enum
?
C#解决方法
Jon双向飞碟已经开始工作上的一个图书馆,编制课程与一个约束
IEnumConstraint
, ,然后代替System.Enum
后建立的。这是我相信,最近的一项可以得到工作围绕这一问题在这个时候。参见:
- 代码项目: http://code.google.com/p/unconstrained-melody/
- 博客入口: http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx
如果这种解决方法是行不通的,你会写你的图书馆作为C++/CLI代码,不限制可以用于一般类型的约束(参见码在我的回答下面。)
解决方案
编辑:库现在可以支撑这个通过ildasm/ilasm: UnconstrainedMelody.
成员C#队以前所说的他们会 喜欢 能够支持 where T : Enum
和 where T : Delegate
, 但是从来没有足够高的优先事项。(我不确定什么样的推理是有限制在第一位,无可否认...)
最实际的解决办法在C#是:
public static bool HasFlags<T>(this T value, T flags) where T : struct
{
if (!(value is Enum))
{
throw new ArgumentException();
}
// ...
}
失去的编写时检查"enum性",但会保持检查,你们采用相同类型,在这两个地方。它具有执行时的惩罚的检查以及,当然。你可以避免,执行时的惩罚之后的第一个电话通过使用一个通用的嵌套的类型实现其引发的例外,在一个静态的构造:
public static bool HasFlags<T>(this T value, T flags) where T : struct
{
if (!(value is Enum))
{
throw new ArgumentException();
}
return EnumHelper<T>.HasFlags(value, flags);
}
private class EnumHelper<T> where T : struct
{
static EnumHelper()
{
if (!typeof(Enum).IsAssignableFrom(typeof(T))
{
throw new InvalidOperationException(); // Or something similar
}
}
internal static HasFlags(T value, T flags)
{
...
}
}
作为希腊提到,可以编写方法在C++/CLI然后参照这类图书馆从C#作为另一种选择。
其他提示
实际上,这是可能的,与一个丑恶伎俩。然而,它不能用于扩展的方法。
public abstract class Enums<Temp> where Temp : class {
public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
return (TEnum)Enum.Parse(typeof(TEnum), name);
}
}
public abstract class Enums : Enums<Enum> { }
Enums.Parse<DateTimeKind>("Local")
如果你想,你可以给 Enums<Temp>
一个私人的构造和公共嵌套抽象的继承类 Temp
作为 Enum
, ,防止继承的版本对于非枚举。
我无法抗拒具有在C++的工作,并且由于我得到了它的工作,我想我会分享它与其他的你!
这里是C++代码(C++很生疏因此,请指出任何错误,特别是如何的参数界定):
#include "stdafx.h"
using namespace System;
using namespace System::Runtime::CompilerServices;
namespace Blixt
{
namespace Utilities
{
[Extension]
public ref class EnumUtility abstract sealed
{
public:
generic <typename T> where T : value class, Enum
[Extension]
static bool HasFlags(T value, T flags)
{
__int64 mask = Convert::ToInt64(flags);
return (Convert::ToInt64(value) & mask) == mask;
}
};
}
}
和C#代码进行测试(控制台应用程序):
using System;
using Blixt.Utilities;
namespace Blixt.Playground
{
[Flags]
public enum Colors : byte
{
Black = 0,
Red = 1,
Green = 2,
Blue = 4
}
[Flags]
public enum Tastes : byte
{
Nothing = 0,
Sour = 1,
Sweet = 2,
Bitter = 4,
Salty = 8
}
class Program
{
static void Main(string[] args)
{
Colors c = Colors.Blue | Colors.Red;
Console.WriteLine("Green and blue? {0}", c.HasFlags(Colors.Green | Colors.Red));
Console.WriteLine("Blue? {0}", c.HasFlags(Colors.Blue));
Console.WriteLine("Green? {0}", c.HasFlags(Colors.Green));
Console.WriteLine("Red and blue? {0}", c.HasFlags(Colors.Red | Colors.Blue));
// Compilation error:
//Console.WriteLine("Sour? {0}", c.HasFlags(Tastes.Sour));
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
}
你可以实现这一使用IL织和 ExtraConstraints
让你写这些代码
public static bool HasFlags<[EnumConstraint] T>(this T value, T flags)
{
// ...
}
什么得到汇编的
public static bool HasFlags<T>(this T value, T flags)
where T : System.Enum
{
// ...
}