何よりもまず、これは本当に奇妙なことです。最初に別のデザインを考えるべきです。今、私のところに来ているカップルがいます。
とにかく、リフレクションを使用して、達成しようとしていることを達成できます。、 よくほとんど..
foreach (Dimension dimension in Enum.GetValues(typeof(Dimension)))
{
var r = new ReferenceTable(dimension).referenceItems;
var qry = TVRawDataList.Where(p => !r.Any(d => IsAMatch(p, dimension, d.Value)))
.ToList();
DimensionItem di = new DimensionItem(qry, dimension);
newDimensions.Add(di);
}
bool IsAMatch<T>(TVRawDataRecord obj, Dimension dimension, T valueToMatch)
{
return valueToMatch == dimension.MapToTvRecordProperty<T>(obj);
}
T MapToTvRecordProperty<T>(this Dimension dimension, TVRawDataRecord obj)
{
return obj.GetPropertyValue<T>(dimension.ToString());
}
T GetPropertyValue<T>(this TVRawDataRecord obj, string propertyName)
{
var property = typeof(TVRawDataRecord).GetProperty(propertyName);
if (property == null)
return null; //or throw whatever
return (T)property.GetValue(obj, null);
}
厳密にテストされておらず、コンパイルされていません。しかし、これはそれがどのように行われるかについてのアイデアを与えるはずです。GetPropertyValue
関数をより汎用的にすることはできますが、それは別のことです。プロパティの戻り値の型を知る必要があるため、(ディメンション列挙型をクラスのプロパティにマップする) 関数のT
型引数が渡されます。Map
TVRawDataRecord
より良い代替設計は、 if else ロジックを使用して正しい型を返す単純な関数を作成することだと思います。したがってMap
、関数を次のように変更します。
T MapToTvRecordProperty<T>(this Dimension dimension, TVRawDataRecord obj)
{
switch (dimension)
{
case Dimension.BrandVariant:
return obj.BrandVariant;
case Dimension.Creative:
return obj.Creative;
.....
default:
throw;
}
}
利点は、後で変数の名前を変更しても、コードが壊れないことです (リフレクション アプローチとは異なります)。しかし、ここでの問題は、戻り値の型を選択することですT
。戻り値の型が返されるものと一致しないため、2 番目の例はコンパイルされません。すべてのプロパティが同じタイプの場合は、そのタイプを選択できます。それが非常に可変である場合は、最初にプロパティをオブジェクトにキャストし、次に にキャストする必要がありますT
が、それでもリフレクションよりは優れています!!
さらに良いアプローチは、属性を propertyまたはenumに指定することです。
BrandVariant
およびCreative
etc が独自のクラスである場合は、読み取り専用のプロパティを持つインターフェイスをすべて実装することDimension
ができ、テレビ レコード プロパティのそのプロパティにアクセスして、適切なディメンション値を取得できます。