Можно ли имитировать этот код перечисления Java в C # - PullRequest
4 голосов
/ 01 февраля 2012

Можно ли скопировать эту функциональность, предлагая абстрактный метод в перечислении, которому внутренние константы перечисления должны переопределять и предоставлять функциональность?

public enum Logic {
    PAY_DAY {
        @Override
        public void acceptPlayer(Player player) {
            // Perform logic
        }
    },
    COLLECT_CASH {
        @Override
        public void acceptPlayer(Player player) {
            // Perform logic
        }
    }
    ,
    ETC_ETC {
        @Override
        public void acceptPlayer(Player player) {
            // Perform logic
        }
    };

    public abstract void acceptPlayer(Player player);
}

Если не может :: Не могли бы вы предоставить способ, которым я мог бы реализовать множество конкретной логики подобным образом?

Edit :: Я знаю, что перечисления в C # на самом деле не являются "объектами", как в Java, но я хочу выполнить аналогичную логику.

Edit :: Чтобы уточнить, я не хочу предоставлять конкретные классы для каждого конкретного бита логики. IE, создание интерфейса acceptPlayer и создание множества новых классов не подходит

Ответы [ 4 ]

5 голосов
/ 01 февраля 2012

Вот один вариант - не использование перечислений, а что-то похожее - иш ...

public abstract class Logic
{
    public static readonly Logic PayDay = new PayDayImpl();
    public static readonly Logic CollectCash = new CollectCashImpl();
    public static readonly Logic EtcEtc = new EtcEtcImpl();

    // Prevent other classes from subclassing
    private Logic() {}

    public abstract void AcceptPlayer(Player player);

    private class PayDayImpl : Logic
    {
        public override void AcceptPlayer(Player player)
        {
            // Perform logic
        }
    }

    private class CollectCashImpl : Logic
    {
        public override void AcceptPlayer(Player player)
        {
            // Perform logic
        }
    }

    private class EtcEtcImpl : Logic
    {
        public override void AcceptPlayer(Player player)
        {
            // Perform logic
        }
    }
}

Вы говорите , что вы не хотите предоставлять конкретный класс для каждого биталогики - но это в основном то, что вы будете делать в Java в любом случае, просто класс будет немного скрыт от вас.

Вот альтернативный подход с использованием делегатов для изменяющегося поведения:

public sealed class Logic
{
    public static readonly Logic PayDay = new Logic(PayDayAccept);
    public static readonly Logic CollectCash = new Logic(CollectCashAccept);
    public static readonly Logic EtcEtc = new Logic(player => {
        // An alternative using lambdas...
    });

    private readonly Action<Player> accept;

    private Logic(Action<Player> accept)
    {
        this.accept = accept;
    }

    public void AcceptPlayer(Player player)
    {
        accept(player);
    }

    private static void PayDayAccept(Player player)
    {
        // Logic here
    }

    private static void CollectCashAccept(Player player)
    {
        // Logic here
    }
}

В обоих случаях вы по-прежнему получаете фиксированный набор значений - но вы не сможете их включить.Вы могли бы потенциально иметь отдельное «реальное» перечисление, но это было бы немного грязно.

2 голосов
/ 01 февраля 2012

Если вы не хотите использовать интерфейсы и иерархию классов, вы можете использовать делегаты, что-то вроде:

public class Player{}

public static class Logic
{
    public static readonly Action<Player> PAY_DAY = p => Console.WriteLine( "Pay day : " + p.ToString());

    public static readonly Action<Player> COLLECT_CASH = p=> Console.WriteLine(p.ToString ());

    public static void AcceptPlayer( this Action<Player> PlayerAction, Player ActingPlayer )
    {
        PlayerAction(ActingPlayer);
    }
}

class MainClass
{
    public static void Main (string[] args)
    {
        var player = new Player();

        Logic.PAY_DAY.AcceptPlayer( player );
    }
}
0 голосов
/ 02 марта 2019

Мне нравятся преимущества перечислений Java, и я хотел попробовать их смоделировать. Я просмотрел много постов здесь и не смог найти простой способ сделать это, поэтому я придумал следующее. Я не профессионал, поэтому, пожалуйста, прости меня за любые глупые ошибки. Это, как я полагаю, обеспечивает почти всю функциональность перечисления Java (я не писал метод клонирования).

Кроме того, я прошу прощения за длину этого сообщения.

Это абстрактный класс:

#region + Using Directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using TestEnum;

#endregion

namespace TestEnum
{
    public abstract class ACsEnum<T, U, V> :
        IComparable<ACsEnum<T, U, V>>
        where T : ACsEnum<T, U, V>
    {
        static ACsEnum()
        {
            // the static constructor causes
            // early creation of the object
            Count = 0;
        }

        // constructor
        protected ACsEnum(Enum m, V v)
        {
            Enum = m;
            Value = v;
            Ordinal = Count++;
        }

    #region Admin Private fields

        // the list of members
        protected static readonly List<T> members = new List<T>();

    #endregion

    #region Admin Public Properties

        // the enum associated with this class
        public Enum Enum { get; }

        // number of members
        public static int Count { get; private set; }

        // ordinal number of this member (zero based)
        public int Ordinal { get; }

        // a name of this member
        public string Name => ToString();

        // the value attached to the enum
        public U Amount => (U) (IConvertible) Enum;

        // the value of this member - this value is
        // returned from the implicit conversion
        public V Value { get; }

    #endregion

    #region Admin Operator

        public static implicit operator V (ACsEnum<T, U, V> m)
        {
            return m.Value;
        }

    #endregion

    #region Admin Functions

        // compare
        public int CompareTo(ACsEnum<T, U, V> other)
        {
            if (other.GetType() != typeof(T)) { return -1; }

            return Ordinal.CompareTo(other.Ordinal);
        }

        // determine if the name provided is a member
        public static bool IsMember(string name, bool caseSensitive)
        {
            return Find(name, caseSensitive) != null;
        }

        // finds and returns a member
        public static T Find (string name, bool caseSensitive = false)
        {
            if (caseSensitive)
            {
                return members.Find(s => s.ToString().Equals(name));
            }
            else
            {
                return members.Find(s => s.ToString().ToLower().Equals(name.ToLower()));
            }
        }

        // allow enumeration over the members
        public static IEnumerable Members()
        {
            foreach (T m in members)
            {
                yield return m;
            }
        }

        // get the members as an array
        public static T[] Values()
        {
            return members.ToArray();
        }

        // same as Find but throws an exception 
        public static T ValueOf(string name)
        {
            T m = Find(name, true);

            if (m != null) return m;

            throw new InvalidEnumArgumentException();
        }

    #endregion

    #region Admin Overrides

        public override bool Equals(object obj)
        {
            if (obj != null && obj.GetType() != typeof(T)) return false;

            return ((T) obj).Ordinal == Ordinal ;
        }

    #endregion
    }
}

Это метод расширения, чтобы помочь с enum:

namespace TestEnum
{
    // special enum extension that gets the value of an enum
    // 
    public static class EnumEx
    {
        public static dynamic Value(this Enum e)
        {
            switch (e.GetTypeCode())
            {
            case TypeCode.Byte:
                {
                    return (byte) (IConvertible) e;
                }
            case TypeCode.Int16:
                {
                    return (short) (IConvertible) e;
                }
            case TypeCode.Int32:
                {
                    return (int) (IConvertible) e;
                }
            case TypeCode.Int64:
                {
                    return (long) (IConvertible) e;
                }
            case TypeCode.UInt16:
                {
                    return (ushort) (IConvertible) e;
                }
            case TypeCode.UInt32:
                {
                    return (uint) (IConvertible) e;
                }
            case TypeCode.UInt64:
                {
                    return (ulong) (IConvertible) e;
                }
            case TypeCode.SByte:
                {
                    return (sbyte) (IConvertible) e;
                }
            }

            return 0;
        }
    }
}

Это фактический класс enum:

namespace TestEnum
{
    public class Planet : ACsEnum<Planet, byte, double>
    {
    #region Base enum

        // this holds the position from the sun
        public enum planet : byte
        {
            MERCURY = 1,
            VENUS   = 2,
            EARTH   = 3,
            MARS    = 4,
            JUPITER = 5,
            SATURN  = 6,
            URANUS  = 7,
            NEPTUNE = 8,
            PLUTO   = 9
        }

    #endregion

    #region ctror

        // planet enum, mass, radius, orbital period (earth days)
        private Planet(   planet p, double m, double r, double v) : base(p, v)
        {
            Mass = m;
            Radius = r;

            members.Add(this);
        }

    #endregion

    #region enum specific Properties

        public double Mass { get;  }
        public double Radius { get;  }

    #endregion

    #region enum specific Functions

        public static double G = 6.67300E-11;

        public double SurfaceGravity()
        {
            return (G * Mass) / (Radius * Radius);
        }

        public double SurfaceWeight(double otherMass)
        {
            return otherMass * SurfaceGravity();
        }

    #endregion

    #region Overrides

        public override string ToString() => Enum.ToString();

    #endregion

    #region Members

        //                                                          enum      mass            radius       "year"
        public static readonly Planet MERCURY   = new Planet(planet.MERCURY, 3.303e+23     , 2.4397e6   ,     88.0);
        public static readonly Planet VENUS     = new Planet(planet.VENUS  , 4.869e+24     , 6.0518e6   ,    224.7);
        public static readonly Planet EARTH     = new Planet(planet.EARTH  , 5.976e+24     , 6.37814e6  ,    365.2);
        public static readonly Planet MARS      = new Planet(planet.MARS   , 6.421e+23     , 3.3972e6   ,    687.0);
        public static readonly Planet JUPITER   = new Planet(planet.JUPITER, 1.9e+27       , 7.1492e7   ,   4331.0);
        public static readonly Planet SATURN    = new Planet(planet.SATURN , 5.688e+26     , 6.0268e7   ,  10747.0);
        public static readonly Planet URANUS    = new Planet(planet.NEPTUNE, 8.686e+25     , 2.5559e7   ,  30589.0);
        public static readonly Planet NEPTUNE   = new Planet(planet.URANUS , 1.024e+26     , 2.4746e7   ,  59800.0);
        public static readonly Planet PLUTO     = new Planet(planet.PLUTO  , 11.30900e+22  , 1.187e6    ,  90560.0);

    #endregion

    }
}

Наконец, вот пример использования:

using System;
using static TestEnum.Planet;

namespace TestEnum
{
    class Program
    {

        static void Main(string[] args)
        {
            Program p = new Program();

            p.EnumTest();

            Console.WriteLine("\n\nWaiting ...:  ");
            Console.ReadKey();
        }

        private void EnumTest()
        {

            // test:
            // each admin property: count, ordinal, value, name
            // each unique property: APlanet, Mass, Radius, G
            // implicit operator
            // admin functions: 
            // admin overrides:
            // unique properties
            // unique functions

            Console.WriteLine("\nadmin properties\n");
            Console.WriteLine("count     | " + Planet.Count + "  (== 9)");
            Console.WriteLine("ordinal   | " + MERCURY.Ordinal + "  (== 0)");
            Console.WriteLine("name      | " + MERCURY.Name + " (== MERCURY)");
            Console.WriteLine("value     | " + MERCURY.Value + " (== 88 Mercury year)");

            double x = EARTH;

            Console.WriteLine("\nadmin Operator\n");
            Console.WriteLine("Year      | " + x + "  (== 365.2 year)");

            Console.WriteLine("\nadmin functions\n");
            Console.WriteLine("Compare to| " + MERCURY.CompareTo(EARTH) + "  (== -1)");
            Console.WriteLine("IsMember  | " + Planet.IsMember("EARTH", true) + "  (== true)");
            Console.WriteLine("Find      | " + Planet.Find("EARTH", true).Name + "  (== EARTH)");
            Console.WriteLine("ValueOf   | " + Planet.ValueOf("EARTH").Name + "  (== EARTH)");
            Console.WriteLine("Equals    | " + EARTH.Equals(MERCURY) + " (== false => EARTH != MERCURY)");

            Console.WriteLine("\n\nunique admin\n");
            Console.WriteLine("G         | " + Planet.G);

            Console.WriteLine("\nunique properties\n");
            Console.WriteLine("Enum      | " + MERCURY.Enum);
            Console.WriteLine("Mass      | " + MERCURY.Mass);
            Console.WriteLine("Radius    | " + MERCURY.Radius);
            Console.WriteLine("amount    | " + MERCURY.Amount + "  (== 1 MERCURY first planet)");

            Console.WriteLine("\n\nunique functions");

            // typical Java enum usage example

            double earthWeight = 175; // lbs

            double mass = earthWeight / EARTH.SurfaceGravity();

            Console.WriteLine("\ncalc weight via foreach\n");

            foreach (Planet p in Planet.Members())
            {
                Console.WriteLine("Your weight on {0} is {1:F5}",
                    p.Name, p.SurfaceWeight(mass));
            }

            // end, typical Java enum usage example

            // test Values

            Planet[] planets = Planet.Values();

            Console.WriteLine("\ncalc weight  via array\n");

            foreach (Planet p in planets)
            {
                Console.WriteLine("Your weight on {0} is {1:F5}",
                    p.Name, p.SurfaceWeight(mass));
            }

            // test switch
            Planet planet = PLUTO;

            Console.WriteLine("\nuse switch - looking for PLUTO\n");

            switch (planet.Enum)
            {
            case Planet.planet.EARTH:
                {
                    Console.WriteLine("found EARTH\n");
                    break;
                }
            case Planet.planet.JUPITER:
                {
                    Console.WriteLine("found JUPITER\n");
                    break;
                }
            case Planet.planet.PLUTO:
                {
                    Console.WriteLine("found PLUTO\n");
                    break;
                }
            }

            // these will use implicit value
            Console.WriteLine("\ntest comparison checks\n");
            if (EARTH == EARTH)
            {
                Console.WriteLine("\npassed - EARTH == EARTH\n");
            }

            if (MERCURY < EARTH)
            {
                Console.WriteLine("passed - MERCURY < EARTH\n");
            }

            if (PLUTO > EARTH)
            {
                Console.WriteLine("passed - PLUTO > EARTH\n");
            }

            // test enum extension

            Console.WriteLine("\nbonus - enum extension\n");
            Console.WriteLine("PLUTO AsShort| " + Planet.planet.PLUTO.Value() + "  (9th planet)");


            // test ValueOf failure
            Console.WriteLine("\n\nValueOf that fails\n");
            try
            {
                planet = Planet.ValueOf("xxx");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        }
    }
}

Я надеюсь, что это поможет любому, кто хочет предоставить дополнительные функции enum, и, возможно, это поможет кому-то преобразовать их программу из Java в C #

0 голосов
/ 01 февраля 2012

В c # вы делаете это с классами, а не с перечислениями. Создайте базовый класс с виртуальным методом, который вы хотите переопределить.

Каждый член перечисления Java будет подклассом с желаемой реализацией.

Наконец, создайте статическое поле только для чтения в базовом классе для каждого члена перечисления, инициализируя его экземпляром подкласса для этого значения перечисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...