Herkes bir enum genel kısıtlaması olmaması için iyi bir çözüm biliyor?

oy
79

Ne yapmak istiyorum böyle bir şey: Ben kombine bayraklı değerlerle Çeteleler var.

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;
    }
}

Ondan sonra yapabileceği:

MyEnum tester = MyEnum.FlagA | MyEnum.FlagB

if( tester.IsSet( MyEnum.FlagA ) )
    //act on flag a

Maalesef C # 'ın kısıtlamaları hiçbir enum kısıtlaması, sadece sınıf ve yapı sahip olduğu genel. C # yapılar olarak Çeteleler görmez (bunlar değer türleridir olsa bile) bu yüzden böyle uzantı türlerini ekleyemezsiniz.

Herkes bir çözüm biliyor?

Oluştur 10/08/2008 saat 16:14
kaynak kullanıcı
Diğer dillerde...                            


12 cevaplar

oy
16

: Eğer boolean matematik yapmak ints (veya daha büyük olasılıkla uint) bunları atmak zorunda çalışmak genel sayımları için - tipleri belirli numaralandırma olsaydı Darren bu işe yarar

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
Cevap 10/08/2008 saat 21:53
kaynak kullanıcı

oy
1

Ayrıca T test etmek için yansıma kullanabilirsiniz yöntemi içinde, orijinal kodu kullanarak bir enum olan:

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;
    }
}
Cevap 17/08/2008 saat 03:51
kaynak kullanıcı

oy
3

Bunun bir yapı sınırlaması konur yapmak yolu, daha sonra T zamanında bir enum olduğunu kontrol edin. Bu sorunu tamamen ortadan kaldırmaz ama biraz azaltmak gelmez

Cevap 27/07/2009 saat 13:02
kaynak kullanıcı

oy
46

DÜZENLEME: Bu şimdi UnconstrainedMelody sürümü 0.0.0.2 yaşıyor.

(Benim istenen gibi enum kısıtlamaları hakkında blog yayınında . Ben tek başına bir cevap sağlamak amacıyla aşağıdaki temel gerçekleri yer verdik.)

En iyi çözüm bana dahil etmek beklemektir UnconstrainedMelody 1 . Bu gibi "sahte" kısıtlamalarla C # kodu alan bir kütüphane

where T : struct, IEnumConstraint

ve haline döner

where T : struct, System.Enum

Bir postbuild adımı ile.

Yazmak çok zor olmamalı IsSetikisi için ikram rağmen ... Int64tabanlı ve UInt64merkezli bayrakları zor kısmı olabilir. (Bazı yardımcı yöntemler temelde bana bunun bir taban türü varmış gibi herhangi bayraklar enum tedavi için izin geliyor kokusu UInt64.)

Ne davranış çağrılacak eğer isteyeyim

tester.IsSet(MyFlags.A | MyFlags.C)

? O kontrol etmelidir tüm Belirtilen işaretler ayarlanır? Bu benim beklenti olurdu.

Sonra biraz dinlenmek, ... Ben hızla kullanılabilir bir standart kadar kütüphane almak için kullanışlı enum yöntemleri hızlı bir yıldırım sahip umuyorum eve bu gece bunu yapmak çalışacağım.

DÜZENLEME: emin değilim IsSetbu arada, bir isim olarak. Seçenekler:

  • İçerir
  • İçeren
  • HasFlag (veya HasFlags)
  • Isset (kesinlikle bir seçenek)

Düşünceler edilir. Hiçbir şey zaten dokunulmaz edilmeden önce bir süre olacak eminim ...


1 tabii ki, bir yama olarak göndermek veya ...

Cevap 11/09/2009 saat 08:12
kaynak kullanıcı

oy
9

Aslında bu çirkin hile ile mümkündür. Ancak, uzatma yöntemleri için kullanılamaz.

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")

Eğer isterseniz, size verebilir Enums<Temp>bulunan özel yapıcı ve kamu iç içe soyut miras sınıf Tempolarak Enum, sigara çeteleler için kalıtsal sürümlerini engellemek için.

Cevap 13/09/2009 saat 01:41
kaynak kullanıcı

oy
1

İşte sadece çok çılgın bir şey yapmak zorunda kalmadan istediğiniz gibi çalışmak gibi görünüyor kadar yaptığımız bazı kod. Bu Flags olarak ayarlanmış sadece çeteleler sınırlı değil, ama her zaman ihtiyaç olduğuna konan bir çek söz konusu olabilir.

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.");
    }
}
Cevap 13/09/2009 saat 02:57
kaynak kullanıcı

oy
4

Bu orijinal soruya cevap vermez, ama denilen .NET 4'te bir yöntem şimdi var Enum.HasFlag size örnekte yapmaya çalışıyorsun onu yapar ki

Cevap 20/11/2009 saat 10:08
kaynak kullanıcı

oy
8

Bunu kullanarak IL Dokuma ve elde edebilirsiniz ExtraConstraints

Bu kodu yazma izni verir

public class Sample
{
    public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
    {        
    }
    public void MethodWithEnumConstraint<[EnumConstraint] T>()
    {
    }
}

Ne olur derlenmiş

public class Sample
{
    public void MethodWithDelegateConstraint<T>() where T: Delegate
    {
    }

    public void MethodWithEnumConstraint<T>() where T: struct, Enum
    {
    }
}
Cevap 20/07/2012 saat 06:11
kaynak kullanıcı

oy
0

Sadece genel bir sınırlama olarak Enum eklemek istedim.

Bu sadece kullanan küçük bir yardımcı yöntem için olsa ExtraConstraintsbenim için biraz fazla havai olduğunu.

Ben sadece bir yaratmaya karar structkısıtlamayı ve bir çalışma zamanı çek ekleyin IsEnum. Enum T bir değişken dönüştürmek için ilk nesne için döküm.

    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());
    }
Cevap 18/03/2016 saat 05:49
kaynak kullanıcı

oy
0

Birisi jenerik isset ihtiyacı varsa (üzerine geliştirilebilir anında kutunun dışında oluşturulan) ve ya Enum onfly dönüşüm dizesi (EnumConstraint kullanır aşağıda sunulmuştur):

  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);

    }

  }

Birisi hala Enum kodlama kısıtlama oluşturmak için sıcak bir örnek gerekiyorsa:

using System;

/// <summary>
/// would be same as EnumConstraint_T&lt;Enum>Parse&lt;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));
  }

}

Bu kimse yardımcı olur.

Cevap 22/12/2016 saat 06:42
kaynak kullanıcı

oy
5

C # 7.3 olarak enum kısıtlamaları eklemek için yerleşik bir yolu artık var:

public class UsingEnum<T> where T : System.Enum { }

Kaynak: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint

Cevap 11/05/2018 saat 08:33
kaynak kullanıcı

oy
0

C # 7.3 olarak, jenerik türlerinde Enum kısıtlamayı kullanabilirsiniz:

public static TEnum Parse<TEnum>(string value) where TEnum : Enum
{
    return (TEnum) Enum.Parse(typeof(TEnum), value);
}

Bir null enum kullanmak istiyorsanız, orginial yapı sınırlaması terk etmelidir:

public static TEnum? TryParse<TEnum>(string value) where TEnum : struct, Enum
{
    if( Enum.TryParse(value, out TEnum res) )
        return res;
    else
        return null;
}
Cevap 18/05/2018 saat 12:04
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more