Enums'e uzantı yöntemleri ekleme


122

Bu Enum koduna sahibim:

enum Duration { Day, Week, Month };

Bu Enum için bir uzatma yöntemi ekleyebilir miyim?




kısa cevap, evet. Bu özel durumda kullanımını dikkate almak isteyebilirsinizTimeSpan
Jodrell

1
Bir numaralandırma üzerinde uzatma yöntemlerini kullanmak kendimi kirli hissetmeme neden olur. Neyin gerekli olduğunu özetlemek için bir sınıf oluşturun. Bir numaralandırmayı olabildiğince basit tutun. Bununla ilişkili daha fazla mantığa ihtiyacınız varsa, gün, hafta, ay artı uzantı yönteminde bulunabilecek diğer mantıkları içeren bir Süre sınıfı oluşturun.
Jason Evans

2
Bayrak grupları için enum genişletme yöntemlerine sahip olmayı seviyorum. Örneğin maddeleri eğer ben tercih Day.IsWorkday()aşkın (Day & Days.Workday) > 0ile Days.Workdayolarak tanımlanan Monday | Tuesday ... | Friday. İlki bence daha net ve ikincisi tam olarak uygulandı.
Sebastian Werk

Yanıtlar:


114

Bu siteye göre :

Uzantı yöntemleri, ekibinizdeki diğer kişilerin gerçekten keşfedip kullanabileceği şekilde mevcut sınıflar için yöntemler yazmanın bir yolunu sağlar. Numaralandırmaların diğerleri gibi sınıflar olduğu göz önüne alındığında, bunları genişletebilmeniz çok şaşırtıcı olmamalı, örneğin:

enum Duration { Day, Week, Month };

static class DurationExtensions 
{
  public static DateTime From(this Duration duration, DateTime dateTime) 
  {
    switch (duration) 
    {
      case Day:   return dateTime.AddDays(1);
      case Week:  return dateTime.AddDays(7);
      case Month: return dateTime.AddMonths(1);
      default:    throw new ArgumentOutOfRangeException("duration");
    }
  }
}

Bence numaralandırmalar genel olarak en iyi seçenek değil, ama en azından bu, anahtarın bir kısmını merkezileştirmenize / eğer daha iyi bir şey yapana kadar onları biraz daha soyutlamanıza izin veriyor. Değerlerin de aralıkta olup olmadığını kontrol etmeyi unutmayın.

Buradan daha fazlasını Microsft MSDN'de okuyabilirsiniz .


"Numaralandırmalar kötüdür" yorumunun yerinde olmadığına ama gerçekte bir temeli olduğuna inanıyorum. Sizi belirli bağlamlara ve davranışlara kilitledikleri için numaralandırmaların aşırı kullanılmış bir sorun olabileceğini anlıyorum.
Ed Schwehm

1
C # tür numaralandırmalar emer çünkü bu derler ve çalışır:Duration d = 0;
Graham

16
Given that enums are classeshayır sınıf değiller.
Winger Sendon

1
Bu tür bir uzantıyı yalnızca, haftanın günleri ve IsWeekday (), IsWeekendday () gibi uzatma yöntemleri gibi doğrudan enum ile ilgiliyse kullanırım. Ancak sınıfların davranışları özetlemesi amaçlanmıştır, bu nedenle kapsayacak çok fazla veya karmaşık davranış varsa, bir sınıf muhtemelen daha iyidir. Sınırlı ve basitse, kişisel olarak numaralandırma uzantıları bulabilirim. Çoğu tasarım kararında olduğu gibi, seçenekler arasında belirsiz sınırlar vardır (IMO). Uzantıların yalnızca üst düzey statik sınıflarda yapılabileceğini, yuvalanmış sınıflarda yapılamayacağını belirtmek gerekir. Numaranız bir sınıfın parçasıysa, bir sınıf oluşturmanız gerekir.
FreeText

51

Ayrıca, Enum örneğinin yerine Enum türüne bir uzantı yöntemi ekleyebilirsiniz:

/// <summary> Enum Extension Methods </summary>
/// <typeparam name="T"> type of Enum </typeparam>
public class Enum<T> where T : struct, IConvertible
{
    public static int Count
    {
        get
        {
            if (!typeof(T).IsEnum)
                throw new ArgumentException("T must be an enumerated type");

            return Enum.GetNames(typeof(T)).Length;
        }
    }
}

Yukarıdaki uzantı yöntemini aşağıdakileri yaparak çağırabilirsiniz:

var result = Enum<Duration>.Count;

Bu gerçek bir uzatma yöntemi değil. Yalnızca Enum <> System.Enum'dan farklı bir tür olduğu için çalışır.


Sınıf static, tüm yöntemlerinin uzantılar gibi davrandığından emin olabilir mi?
Jatin Sanghvi

15
Gelecekteki okuyucular için: 'nin isim belirsizliği Enum<T>biraz kafa karıştırıcı. Sınıf da çağrılabilir EnumUtils<T>ve yöntem çağrısı olarak çözümlenir EnumUtils<Duration>.Count.
Namoshek

46

Eğer, örneğin söyleyebiliriz Tabii ki, kullanmak istediğiniz DescriptionAttribuesenin üzerinde enumdeğerler:

using System.ComponentModel.DataAnnotations;

public enum Duration 
{ 
    [Description("Eight hours")]
    Day,

    [Description("Five days")]
    Week,

    [Description("Twenty-one days")] 
    Month 
}

Şimdi şöyle bir şey yapabilmek istiyorsunuz:

Duration duration = Duration.Week;
var description = duration.GetDescription(); // will return "Five days"

Uzantı yönteminiz GetDescription()şu şekilde yazılabilir:

using System.ComponentModel;
using System.Reflection;

public static string GetDescription(this Enum value)
{
    FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
    if (fieldInfo == null) return null;
    var attribute = (DescriptionAttribute)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute));
    return attribute.Description;
}

DisplayAttribute Localized GetDescription kullanımım dışında, neredeyse tam olarak örneklediğiniz şey için bir uzantı oluşturmak istiyordum. cheers
George

Bu güzel bir alternatif olsa da ad alanının sadece System.ComponentModel olduğunu düşünüyorum.
TomDestry

Güzel bir bakış açısı ve uygulamayı ve uzantı kodunu gösterdiğiniz için teşekkür ederiz. Biriktirmek için: uygulamanızla, bunu şu şekilde de çağırabilirsiniz: var description = Duration.Week.GetDescription ();
Spencer Sullivan

31

Tüm cevaplar harika, ancak belirli bir numaralandırma türüne uzantı yöntemi eklemekten bahsediyorlar.

Ya tüm numaralandırmalara, açık çevrim yerine geçerli değerden bir int döndürmek gibi bir yöntem eklemek isterseniz?

public static class EnumExtensions
{
    public static int ToInt<T>(this T soure) where T : IConvertible//enum
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("T must be an enumerated type");

        return (int) (IConvertible) soure;
    }

    //ShawnFeatherly funtion (above answer) but as extention method
    public static int Count<T>(this T soure) where T : IConvertible//enum
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("T must be an enumerated type");

        return Enum.GetNames(typeof(T)).Length;
    }
}

Bunun arkasındaki püf IConvertiblenoktası, Devralma Hiyerarşisidir bkz. MDSN

Cevabı için ShawnFeatherly'ye teşekkürler


1
en iyi cevap!
Marco Alves

Aynen. Dahili MyExtention.DoThing(myvalue)myvalue.DoThing()
numarayı

1
Bilginize, C # 7.3 artık
Enum'u

7

Her şey için bir uzantı oluşturabilirsiniz object(bu en iyi uygulama sayılmasa da ). Bir uzatma yöntemini bir public staticyöntem olarak anlayın . Yöntemlerde istediğiniz parametre türünü kullanabilirsiniz.

public static class DurationExtensions
{
  public static int CalculateDistanceBetween(this Duration first, Duration last)
  {
    //Do something here
  }
}

5

MSDN'ye bakın .

public static class Extensions
{
  public static string SomeMethod(this Duration enumValue)
  {
    //Do something here
    return enumValue.ToString("D"); 
  }
}

7
Bir voidenum üzerindeki dönüş değeri biraz tuhaftır. Daha gerçekçi bir örnek düşünürdüm.
psubsee2003

3
@ psubsee2003 Operatörün bunu kendi ihtiyaçlarına uyacak şekilde değiştirmeye yetecek bilgisi var mı? Örnek neden önemli, ilk soruyu cevaplamak için yeterli.
LukeHennerley

3
MSDN'deki kod örneklerini tuhaf bulan tek kişi ben miyim? Ne yapmaya çalıştıklarını anlamak için çoğu zaman gerçek bir çabaya ihtiyacınız var!
Yığın

0

c # https://github.com/simonmau/enum_ext için bir enum uzantısı yaptık

Bu sadece tipafeenum için bir uygulama, ancak harika çalışıyor, bu yüzden paylaşmak için bir paket hazırladık - onunla eğlenin

public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
{
    public static readonly Weekday Monday = new Weekday(1, "--Monday--");
    public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
    public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
    ....

    private Weekday(int id, string name) : base(id, name)
    {
    }

    public string AppendName(string input)
    {
        return $"{Name} {input}";
    }
}

Örneğin faydasız olduğunu biliyorum, ama fikri anladınız;)


0

Basit bir çözüm.

public static class EnumExtensions
{
    public static int ToInt(this Enum payLoad) {

        return ( int ) ( IConvertible ) payLoad;

    }
}

int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.