それぞれが2つのサブオブジェクトを持ついくつかの定数オブジェクトを宣言したいのですが、これらenum
を組織的な目的でに保存したいと思います。
C#でこのようなことをすることは可能ですか?
enum Car
{
carA = { 'ford', 'red' }
carB = { 'bmw', 'black' }
carC = { 'toyota', 'white' }
}
いいえ、C#言語ではそれができません。
あなたは作成することができます
Dictionary<Car, List<string>> cars;
あなたはそれにエントリを追加します
cars = new Dictionary<Car, List<String>>();
cars.Add(Car.carA, new List<String>() { "ford", "red" });
ただし、「フォード」と「赤」の概念を組み合わせている場合は、そのことを表すオブジェクトの作成を検討することをお勧めします。
public class CarDetails
{
public string Maker { get; set; }
public string Color { get; set; }
}
次に、Dictionary
オブジェクトは次のようになります
Dictionary<Car, CarDetails> cars;
cars = new Dictionary<Car.carA, CarDetails>();
cars.Add(Car.carA, new CarDetails() { Maker = "ford", Color = "red" });
いいえ、これは不可能です。静的クラスを定義できます
public static class Car
{
public static readonly ReadOnlyCollection<string> carA = Array.AsReadOnly(new[]{"ford","red"});
public static readonly ReadOnlyCollection<string> carB = Array.AsReadOnly(new[]{"bmw","black"});
public static readonly ReadOnlyCollection<string> carC = Array.AsReadOnly(new[]{"toyota","white"});
}
列挙型の不変性プロパティを保持するためにReadOnlyCollection<string>
、の代わりに使用しました。string[]
Car
これは、の各プロパティがのインスタンスであるという条件を満たしていませんCar
。プライベートコンストラクターと静的インスタンスを使用して、カスタム列挙型クラスを使用して必要なものを取得することもできます。Jimmy Bogardには、実装例と基本クラスがhttp://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/で入手できます。彼は拡張可能な基本クラスを提供します。これを頻繁に行う場合は、これを調べる必要があります。ただし、アイデアが浮かんだので、データでこのアプローチを使用する単純な実装は次のようになります。
public sealed class Car : IEquatable<Car> {
// declare and define each of your constants
public static readonly Car carA = new Car("ford", "red");
public static readonly Car carB = new Car("bmw", "black");
public static readonly Car carC = new Car("toyota", "white");
// define an instance-scoped value object to hold your subObjects
private readonly Tuple<string,string> subObjects;
// a private constructor ensures that all your instances will be constant
// and will be defined from within Car
private Car(string make, string color){
// require valid sub objects
if(string.IsNullOrEmpty(make))throw new ArgumentException("Invalid Make","make");
if(string.IsNullOrEmpty(color))throw new ArgumentException("Invalid Color","color");
// create a subObjects tuple to hold your values to simplify value comparison
this.subObjects = Tuple.Create(make,color);
}
// declare public accessors for your
public string Make { get { return this.subObjects.Item1; } }
public string Color { get { return this.subObjects.Item2; } }
// override Equality for value equality, and resulting consistency across AppDomains
public override bool Equals(object obj){ return obj is Car && this.Equals((Car)obj); }
public bool Equals(Car otherCar){ return otherCar != null && this.subObjects.Equals(otherCar.subObjects); }
public override int GetHashCode(){ return this.subObjects.GetHashCode(); }
public static bool operator ==(Car left, Car right){ return left == null ? right == null : left.Equals(right); }
public static bool operator !=(Car left, Car right){ return !(left == right); }
// override ToString() to provide view of values
public override string ToString(){ return string.Format("Car({0},{1})",Make,Color); }
}
これで、を使用するのと同じ方法でアクセスできますenum
。例えば、
void Main(){
var blackBeamer = Car.carC;
Console.WriteLine("carC is a " + blackBeamer.Color +" " + blackBeamer.Make);
}
いいえ。
まず、C#の列挙型は実際には整数値であり、文字列ではありません。
第二に、列挙型の各値は単一の値のみを持つことができます。
ただし、各列挙値に整数値を指定することもできます。これにより、列挙内の複数の要素が同じ整数値を持つことができます。
public enum Car
{
Ford = 1,
Red = 1,
Bmw = 2,
Black = 2
// etc.
}
しかし、あなたが本当に探しているのは辞書のようです。
列挙型の値は常に整数で表されます。別のタイプ(文字列配列など)を使用することはできません。
同様の結果を得るには、次のようにすることができます。
Dictionary<Car, string[]> cars;
cars = new Dictionary<Car, string[]>();
cars.Add(Car.carA, new string[]{"ford", "red"});
cars.Add(Car.carB, new string[]{"bmw", "black"});
cars.Add(Car.carC, new string[]{"toyota", "white"});
ただし、これは、列挙型をこのような文字列にマップする必要がある場合にのみ行う必要があります。車のメーカーや色など、さまざまな「モノ」を混ぜているようです。次のようなことを考える必要があります。
enum Make {
Ford,
BMW,
Toyota
}
enum Color {
Red,
Black,
White
}
車を次のように表します。
struct Car {
Make make;
Color color;
public Car(Make m, Color c) { make = m; color = c; }
}
およびリストは次のとおりです。
Car[] cars = new Car[]{new Car(Make.Ford, Color.Red), new Car(Make.BMW, Make.Black), new Car(Make.Toyota, Make.White)};
別のアプローチはフラグ列挙型です:
[Flags]
enum Car
{
None = 0,
ModelFord = 1,
ModelBmw = 2,
ModelToyota = 4,
ColorRed = 8,
ColorBlack = 16,
carA = ModelFord | ColorRed,
carB = ModelBmw | ColorBlack,
carC = ModelToyota | ColorBlack
}
これは単なるサンプルであることに注意してください。単一の列挙型(この場合は車のモデルと色)にプロパティのタイプを混在させないようにする必要があります。
Car
として機能させるためのちょっとしたコツは、次のようenum
に定義します。
internal enum Maker
{
Ford, Bmw, Toyota,
}
internal enum Color
{
Red, Black, White
}
次に、構造体を構築しCar
ます。
public struct Car
{
private readonly Maker _maker;
private readonly Color _color;
public static Car CarA = new Car(Maker.Ford, Color.Red);
public static Car CarB = new Car(Maker.Bmw, Color.Black);
public static Car CarC = new Car(Maker.Toyota, Color.White);
private Car(Maker maker, Color color)
{
_maker = maker;
_color = color;
}
public static bool operator ==(Car car1, Car car2)
{
return car1._maker == car2._maker && car1._color == car2._color;
}
public static bool operator !=(Car car1, Car car2)
{
return !(car1 == car2);
}
}
したがって、次を使用できます。
Car a = Car.CarA;
bool flag = a == Car.CarB;
静的クラスを使用して、追加データを表示する拡張メソッドを格納できます。例えば:
enum Car
{
CarA, CarB, CarC
}
public static class Cars
{
public static string[] GetDetails(this Car car)
{
switch (car)
{
case CarA: return new[] { "ford", "red" };
case CarB: return new[] { "bmw", "black" };
case CarC: return new[] { "toyota", "white" };
}
}
}
そうは言っても、このために文字列配列を返すことは私にはあまり意味がありません。代わりに、2つの拡張メソッドを宣言します。1つはmake用、もう1つはcolor用です。
public static class Cars
{
public static string GetMake(this Car car)
{
switch (car)
{
case CarA: return "ford";
case CarB: return "bmw";
case CarC: return "toyota";
}
}
public static string GetColor(this Car car)
{
switch (car)
{
case CarA: return "red";
case CarB: return "black";
case CarC: return "white";
}
}
}
次に、次のように使用できます。
Car car = Car.CarA;
string make = car.GetMake();
string color = car.GetColor();
属性の使用法はどうですか?
enum Cars{
[Make("A Make"), Color("A Color")]
CarA,
[Make("B Make"), Color("B Color")]
CarB
}
次に、このように属性を定義します。
public class MakeAttribute : Attribute
{
public readonly Make make;
public MakeAttribute (Make make)
{
this.make = make;
}
}
車のタイプに拡張機能を追加して、make属性を取得します
public static string GetMake(this Car car)
{
var makeAttr = (MakeAttribute[])car.GetType().GetField(car.ToString()).GetCustomAttributes(typeof(MakeAttribute), false))[0];
return makeAttr.make;
}
そして、このゲッターを呼び出すには、
Cars.CarA.GetMake()