Bagaimana cara menambahkan metode ekstensi ke Enums

122

Saya memiliki kode Enum ini:

enum Duration { Day, Week, Month };

Dapatkah saya menambahkan metode ekstensi untuk Enum ini?

pengguna2110292
sumber
1
Pernahkah kamu melihat ini? stackoverflow.com/questions/2422113/…
badpanda
jawaban singkatnya, ya. Dalam kasus khusus ini, Anda mungkin ingin mempertimbangkan penggunaanTimeSpan
Jodrell
1
Menggunakan metode ekstensi pada enum akan membuat saya merasa kotor. Buat kelas untuk merangkum apa yang dibutuhkan. Buat enum sesederhana mungkin. Jika Anda memerlukan lebih banyak logika yang terkait dengannya, buat kelas Durasi yang memperlihatkan hari, minggu, bulan plus berisi logika lain yang mungkin ada dalam metode ekstensi.
Jason Evans
2
Saya suka memiliki metode ekstensi enum untuk grup bendera. Saya lebih suka kalau klausa misalnya Day.IsWorkday()lebih (Day & Days.Workday) > 0dengan Days.Workdaydidefinisikan sebagai Monday | Tuesday ... | Friday. Yang pertama lebih jelas menurut saya dan justru yang terakhir diimplementasikan.
Sebastian Werk

Jawaban:

114

Menurut situs ini :

Metode ekstensi menyediakan cara untuk menulis metode untuk kelas yang ada dengan cara yang mungkin ditemukan dan digunakan oleh orang lain di tim Anda. Mengingat bahwa enum adalah kelas seperti yang lain, seharusnya tidak terlalu mengejutkan jika Anda dapat memperluasnya, seperti:

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

Saya pikir enum bukanlah pilihan terbaik secara umum tetapi setidaknya ini memungkinkan Anda memusatkan beberapa sakelar / jika menangani dan mengabstraksi mereka sedikit sampai Anda dapat melakukan sesuatu yang lebih baik. Ingatlah untuk memeriksa bahwa nilainya juga dalam kisaran.

Anda dapat membaca lebih lanjut di sini di Microsft MSDN.

Satu Kru
sumber
Saya percaya komentar "enum is evil" tidak pada tempatnya tetapi memiliki dasar dalam kenyataan. Saya menemukan bahwa enum bisa menjadi masalah jika digunakan secara berlebihan, karena enum semacam mengunci Anda dalam konteks dan perilaku tertentu.
Ed Schwehm
1
Enums di C # jenis payah karena ini mengkompilasi dan berjalan:Duration d = 0;
Graham
16
Given that enums are classestidak, mereka bukan kelas.
Pemain sayap Sendon
1
Saya menggunakan ekstensi semacam ini hanya jika itu tentang enum secara langsung, seperti hari dalam seminggu dan metode ekstensi IsWeekday (), IsWeekendday (). Tetapi kelas dimaksudkan untuk merangkum perilaku, jadi jika ada banyak atau perilaku rumit untuk diringkas, kelas mungkin lebih baik. Jika terbatas dan dasar, saya pribadi menemukan ekstensi pada enum oke. Seperti kebanyakan keputusan desain, ada batasan fuzzy antara pilihan (IMO). Perlu dicatat bahwa ekstensi hanya dapat dilakukan pada kelas statis tingkat atas, bukan kelas bersarang. Jika enum Anda adalah bagian dari kelas, Anda harus membuat kelas.
FreeText
51

Anda juga dapat menambahkan metode ekstensi ke tipe Enum daripada contoh Enum:

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

Anda dapat menjalankan metode ekstensi di atas dengan melakukan:

var result = Enum<Duration>.Count;

Ini bukan metode ekstensi yang sebenarnya. Ini hanya berfungsi karena Enum <> adalah tipe yang berbeda dari System.Enum.

ShawnFeatherly
sumber
Bisakah kelas staticmemastikan semua metodenya berperilaku seperti ekstensi?
Jatin Sanghvi
15
Bagi pembaca yang akan datang: ambiguitas nama Enum<T>agak membingungkan. Kelas juga bisa dipanggil EnumUtils<T>dan pemanggilan metode akan diselesaikan menjadi EnumUtils<Duration>.Count.
Namoshek
46

Tentu saja Anda dapat, katakanlah misalnya, Anda ingin menggunakan DescriptionAttribuepada enumnilai Anda :

using System.ComponentModel.DataAnnotations;

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

    [Description("Five days")]
    Week,

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

Sekarang Anda ingin dapat melakukan sesuatu seperti:

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

Metode ekstensi Anda GetDescription()dapat ditulis sebagai berikut:

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;
}
Ditumpuk
sumber
saya sedang mencari untuk membuat ekstensi untuk hampir persis apa yang Anda sampel lakukan, kecuali saya menggunakan DisplayAttribute Localized GetDescription. bersulang
George
Ini adalah alternatif yang bagus, meskipun menurut saya namespace hanya System.ComponentModel?
TomDestry
Perspektif yang bagus dan terima kasih telah menunjukkan implementasi serta kode ekstensi. Untuk menambahkan: dengan implementasi Anda, Anda juga bisa menyebutnya seperti ini: var description = DurationWeek.GetDescription ();
Spencer Sullivan
31

Semua jawaban bagus, tetapi mereka berbicara tentang menambahkan metode ekstensi ke jenis enum tertentu.

Bagaimana jika Anda ingin menambahkan metode ke semua enum seperti mengembalikan int dari nilai saat ini alih-alih casting eksplisit?

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

Trik di belakangnya IConvertibleadalah lihat Hirarki Warisannya MDSN

Terima kasih kepada ShawnFeatherly atas jawabannya

Basheer AL-MOMANI
sumber
1
jawaban terbaik!
Marco Alves
Dito. Ini berfungsi jika saya memanggil ekstensi secara langsung (misalnya MyExtention.DoThing(myvalue)) tetapi tidak benar-benar melampirkan ke enum (misalnya myvalue.DoThing())
Sinaesthetic
1
FYI, C # 7.3 sekarang mendukung Enum sebagai batasan tipe generik
redtetrahedron
7

Anda dapat membuat ekstensi untuk apa pun, bahkan object(meskipun itu tidak dianggap sebagai praktik terbaik ). Pahami metode ekstensi hanya sebagai public staticmetode. Anda dapat menggunakan tipe parameter apa pun yang Anda suka pada metode.

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

Lihat MSDN .

public static class Extensions
{
  public static string SomeMethod(this Duration enumValue)
  {
    //Do something here
    return enumValue.ToString("D"); 
  }
}
LukeHennerley
sumber
7
Nilai voidkembali pada enum agak aneh. Saya akan memikirkan sampel yang lebih realistis.
psubsee2003
3
@ psubsee2003 OP pasti memiliki pengetahuan yang cukup untuk mengubah ini agar sesuai dengan kebutuhannya? Mengapa sampel itu penting, itu cukup untuk menjawab pertanyaan awal.
LukeHennerley
3
Apakah saya satu-satunya yang menganggap contoh kode di MSDN aneh? Sebagian besar waktu Anda membutuhkan upaya nyata untuk memahami apa yang mereka coba lakukan!
Ditumpuk
0

kita baru saja membuat ekstensi enum untuk c # https://github.com/simonmau/enum_ext

Ini hanya implementasi untuk typesafeenum, tetapi berfungsi dengan baik sehingga kami membuat paket untuk dibagikan - bersenang-senanglah dengannya

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

Saya tahu contohnya agak tidak berguna, tetapi Anda mengerti;)

simonmau
sumber
0

Solusi sederhana.

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

        return ( int ) ( IConvertible ) payLoad;

    }
}

int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);
M. Hamza Rajput
sumber