はい、あなたはこれを得ることができます:
BuildCar(Cars.Ferrari.Enzo)
しかし、あなたはこれを手に入れるつもりはありません:
enum Cars
{
Ford { Corsair, Cortina, Galaxy, GT },
Ferrari { Testarossa, California, Enzo },
...
}
あなたができることは、ある種のツリー構造でインスタンスを公開するプライベートコンストラクターを備えた封印されたクラスです。そのためには、いくつかのヘルパークラスが必要になります。
次のコードが機能します。
using System;
namespace _2DEnum
{
public class Example
{
public void BuildCar(Cars car)
{
GC.KeepAlive(car);
}
public void ExampleUse()
{
BuildCar(Cars.Ferrari.Enzo);
}
}
public sealed class Cars
{
private readonly string _value;
private Cars(string value)
{
if (ReferenceEquals(value, null))
{
throw new ArgumentNullException("value");
}
else
{
_value = value;
}
}
public override string ToString()
{
return _value;
}
public static class Ferrari
{
private static readonly Cars _California = new Cars("California");
private static readonly Cars _Enzo = new Cars("Enzo");
private static readonly Cars _Testarossa = new Cars("Testarossa");
public static Cars California
{
get { return Ferrari._California; }
}
public static Cars Enzo
{
get { return Ferrari._Enzo; }
}
public static Cars Testarossa
{
get { return Ferrari._Testarossa; }
}
}
public static class Ford
{
private static readonly Cars _Corsair = new Cars("Corsair");
private static readonly Cars _Cortina = new Cars("Cortina");
private static readonly Cars _Galaxy = new Cars("Galaxy");
private static readonly Cars _GT = new Cars("GT");
public static Cars Corsair
{
get { return Ford._Corsair; }
}
public static Cars Cortina
{
get { return Ford._Cortina; }
}
public static Cars Galaxy
{
get { return Ford._Galaxy; }
}
public static Cars GT
{
get { return Ford._GT; }
}
}
}
}
次に、いくつかのテキスト変換テンプレートを使用して、列挙型のように入力できるようにすることができます。
@Euphoricへの称賛...私は過剰分析バッジが必要です。
テキスト変換テンプレート!
この2D列挙型を生成するコードを保持するファイルEnum2D.ttincludeと、Cars.ttなどの各「2D列挙型」のファイルを使用するT4のソリューションを作成しました。
最初のEnum2D.ttinclude:
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #><#+
public string BuildEnum2D
(
string namespaceName,
string enumName,
IEnumerable<Tuple<string, IEnumerable<string>>> items
)
{
string head =
@"
using System;
namespace @namespace
{
public sealed class @enum
{
private readonly string _value;
private @enum(string value)
{
if (ReferenceEquals(value, null))
{
throw new ArgumentNullException(""value"");
}
else
{
_value = value;
}
}
public override string ToString()
{
return _value;
}";
head = head.Replace("@namespace", namespaceName);
head = head.Replace("@enum", enumName);
StringBuilder sb = new StringBuilder();
sb.Append(head);
foreach (var item in items)
{
sb.Append(
@"
public static class " + item.Item1 +
@"
{"
);
foreach (var entry in item.Item2)
{
sb.Append(
@"
private static readonly Cars _" + entry + @" = new Cars(""" + entry +
@""");"
);
}
foreach (var entry in item.Item2)
{
sb.Append(
@"
public static Cars " + entry + @"
{
get { return _" + entry + @"; }
}"
);
}
sb.Append(
@"
}" );
}
sb.Append(
@"
}
}"
);
return "// <auto-generated />" + "\r\n" + sb.ToString();
}
#>
ご覧のとおり、このファイルはBuildEnum2D
、パラメーターを指定して2D列挙型のコードを生成することのみを目的とした関数を定義しています。今必要なのはそれを呼び出すことです。そのために、Cars.ttを次のように使用します。
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="Enum2D.ttinclude" #>
<#@ output extension=".cs" #><#=
BuildEnum2D
(
"Enum2DTest",
"Cars",
new Tuple<string, IEnumerable<string>>[]
{
new Tuple<string, IEnumerable<string>>
(
"Ferrari",
new string[]
{
"California",
"Enzo",
"Testarossa"
}
),
new Tuple<string, IEnumerable<string>>
(
"Ford",
new string[]
{
"Corsair",
"Cortina",
"Galaxy",
"GT"
}
)
}
)
#>
ご覧のとおり、ファイルEnum2D.ttincludeをインクルードしてから、関数Build2DEnumを呼び出します。パラメーターは、名前空間、列挙型名、およびアイテムです。このようにして、これらの2D列挙型をさらに作成できるようになり、ttファイルを維持するのにそれほど苦労しないことを願っています。
乾杯!