任何人都知道一个很好的解决方法缺乏一个枚举,一般的约束?
题
什么我想要做的就是像这样的东西:我枚举的有标记的价值观。
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
where T:enum //the constraint I want that doesn't exist in C#3
{
return (input & matchTo) != 0;
}
}
那么我能做的事:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
不幸的是,C#'s泛里约束没有enum限制,只有类和结构。C#没见枚举,作为结构(即使他们是值类型),所以我不能增加扩展类型,如此。
任何人都不会知道的一个解决方法?
解决方案
编辑:这是现在生活在版0.0.0.2的UnconstrainedMelody.
(作为请求对我的 博客中约约束enum.我已经包括的基本情况下,为了一个独立的回答。)
最好的解决办法是等待我把它包括在 UnconstrainedMelody1.这是一个图书馆,这需要C#代码"假"的约束,例如
where T : struct, IEnumConstraint
并把它变成
where T : struct, System.Enum
通过生成后的步骤。
应该不会太难以写信 IsSet
...虽然饮用于两个 Int64
基于和 UInt64
基于的标志可能是棘手的一部分。(我闻到了一些辅助方法,基本上允许我对待的任何标志枚举,如果它有一个基本类型的 UInt64
.)
你会怎么想的行为可以如果你被称为
tester.IsSet(MyFlags.A | MyFlags.C)
?它应该检查 所有 指定标志的设置是?这将是我的期望。
我将试图做到这一点回家的路上今晚...我希望有一个快速的闪电战在有用的枚举的方法来获得的库达到一个可用的标准很快,然后放松一下。
编辑:我不知道 IsSet
作为一个名称,由的方式。选项:
- 包括
- 包含
- 显示(或HasFlags)
- IsSet(这当然是一个选项)
想法值得欢迎的。我肯定这将是一段时间之前任何事都落在石头无论如何...
1 或者提交它作为一个补丁,当然...
其他提示
戴伦,那就会工作如果这些类型的具体枚举--对一般枚举的工作,你必须把他们丢到整数(或更可能uint)做的布尔数学:
public static bool IsSet( this Enum input, Enum matchTo )
{
return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
作为C#7.3,现在有一个内置的方式来增加枚举的制约因素:
public class UsingEnum<T> where T : System.Enum { }
实际上,这是可能的,与一个丑恶伎俩。然而,它不能用于扩展的方法。
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.IsSet<DateTimeKind>("Local")
如果你想,你可以给 Enums<Temp>
一个私人的构造和公共嵌套抽象的继承类 Temp
作为 Enum
, ,防止继承的版本对于非枚举。
你可以实现这一使用IL织和 ExtraConstraints
让你写这些代码
public class Sample
{
public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
{
}
public void MethodWithEnumConstraint<[EnumConstraint] T>()
{
}
}
什么得到汇编的
public class Sample
{
public void MethodWithDelegateConstraint<T>() where T: Delegate
{
}
public void MethodWithEnumConstraint<T>() where T: struct, Enum
{
}
}
这没有答案的原来的问题,但现在有一个方法。净4叫 枚举。显示 这没什么你想做你的实例
我做的方式,它是把一种结构约束,然后检查,T是一个枚举,在运行时间。这并不消除该问题完全,但它并减少这些
作为C#7.3,可以使用Enum约束一般类型:
public static TEnum Parse<TEnum>(string value) where TEnum : Enum
{
return (TEnum) Enum.Parse(typeof(TEnum), value);
}
如果你想使用一个可以为空枚举,你必须离开orginial结构的约束:
public static TEnum? TryParse<TEnum>(string value) where TEnum : struct, Enum
{
if( Enum.TryParse(value, out TEnum res) )
return res;
else
return null;
}
用你的原始代码,内的方法还可以使用反射测试,T是一个枚举:
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Must be an enum", "input");
}
return (input & matchTo) != 0;
}
}
这里的一些代码,我只是做了起来,似乎工作就像你想要的,而无需做任何事情太疯狂了。它不仅限于枚举的组作为标志,但没有总是可以检查放在如果需要的话。
public static class EnumExtensions
{
public static bool ContainsFlag(this Enum source, Enum flag)
{
var sourceValue = ToUInt64(source);
var flagValue = ToUInt64(flag);
return (sourceValue & flagValue) == flagValue;
}
public static bool ContainsAnyFlag(this Enum source, params Enum[] flags)
{
var sourceValue = ToUInt64(source);
foreach (var flag in flags)
{
var flagValue = ToUInt64(flag);
if ((sourceValue & flagValue) == flagValue)
{
return true;
}
}
return false;
}
// found in the Enum class as an internal method
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return (ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture);
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
}
throw new InvalidOperationException("Unknown enum type.");
}
}
如果有人需要一般IsSet(创造出来的盒子在飞行可能改善),或串枚举onfly转换(即采用EnumConstraint下文提出):
public class TestClass
{ }
public struct TestStruct
{ }
public enum TestEnum
{
e1,
e2,
e3
}
public static class TestEnumConstraintExtenssion
{
public static bool IsSet<TEnum>(this TEnum _this, TEnum flag)
where TEnum : struct
{
return (((uint)Convert.ChangeType(_this, typeof(uint))) & ((uint)Convert.ChangeType(flag, typeof(uint)))) == ((uint)Convert.ChangeType(flag, typeof(uint)));
}
//public static TestClass ToTestClass(this string _this)
//{
// // #generates compile error (so no missuse)
// return EnumConstraint.TryParse<TestClass>(_this);
//}
//public static TestStruct ToTestStruct(this string _this)
//{
// // #generates compile error (so no missuse)
// return EnumConstraint.TryParse<TestStruct>(_this);
//}
public static TestEnum ToTestEnum(this string _this)
{
// #enum type works just fine (coding constraint to Enum type)
return EnumConstraint.TryParse<TestEnum>(_this);
}
public static void TestAll()
{
TestEnum t1 = "e3".ToTestEnum();
TestEnum t2 = "e2".ToTestEnum();
TestEnum t3 = "non existing".ToTestEnum(); // default(TestEnum) for non existing
bool b1 = t3.IsSet(TestEnum.e1); // you can ommit type
bool b2 = t3.IsSet<TestEnum>(TestEnum.e2); // you can specify explicite type
TestStruct t;
// #generates compile error (so no missuse)
//bool b3 = t.IsSet<TestEnum>(TestEnum.e1);
}
}
如果有人仍然需要例子热创建枚举的编码的约束:
using System;
/// <summary>
/// would be same as EnumConstraint_T<Enum>Parse<EnumType>("Normal"),
/// but writen like this it abuses constrain inheritence on System.Enum.
/// </summary>
public class EnumConstraint : EnumConstraint_T<Enum>
{
}
/// <summary>
/// provides ability to constrain TEnum to System.Enum abusing constrain inheritence
/// </summary>
/// <typeparam name="TClass">should be System.Enum</typeparam>
public abstract class EnumConstraint_T<TClass>
where TClass : class
{
public static TEnum Parse<TEnum>(string value)
where TEnum : TClass
{
return (TEnum)Enum.Parse(typeof(TEnum), value);
}
public static bool TryParse<TEnum>(string value, out TEnum evalue)
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
evalue = default(TEnum);
return Enum.TryParse<TEnum>(value, out evalue);
}
public static TEnum TryParse<TEnum>(string value, TEnum defaultValue = default(TEnum))
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
Enum.TryParse<TEnum>(value, out defaultValue);
return defaultValue;
}
public static TEnum Parse<TEnum>(string value, TEnum defaultValue = default(TEnum))
where TEnum : struct, TClass // struct is required to ignore non nullable type error
{
TEnum result;
if (Enum.TryParse<TEnum>(value, out result))
return result;
return defaultValue;
}
public static TEnum Parse<TEnum>(ushort value)
{
return (TEnum)(object)value;
}
public static sbyte to_i1<TEnum>(TEnum value)
{
return (sbyte)(object)Convert.ChangeType(value, typeof(sbyte));
}
public static byte to_u1<TEnum>(TEnum value)
{
return (byte)(object)Convert.ChangeType(value, typeof(byte));
}
public static short to_i2<TEnum>(TEnum value)
{
return (short)(object)Convert.ChangeType(value, typeof(short));
}
public static ushort to_u2<TEnum>(TEnum value)
{
return (ushort)(object)Convert.ChangeType(value, typeof(ushort));
}
public static int to_i4<TEnum>(TEnum value)
{
return (int)(object)Convert.ChangeType(value, typeof(int));
}
public static uint to_u4<TEnum>(TEnum value)
{
return (uint)(object)Convert.ChangeType(value, typeof(uint));
}
}
希望这可以帮助别人。
我只是想添加枚举,作为一般的约束。
虽然这只是一个微小的辅助方法的使用 ExtraConstraints
是有点太多的开销为我。
我决定只是创建一个 struct
约束,并添加一个运行时间检查 IsEnum
.换一个变量T枚举,我投反对的第一个。
public static Converter<T, string> CreateConverter<T>() where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException("Given Type is not an Enum");
return new Converter<T, string>(x => ((Enum)(object)x).GetEnumDescription());
}