まずタイトルが汚いことをお詫びします。うまく言葉にできないので、状況を説明します。
次のようなさまざまな製品を比較できる製品の比較エンジンを作成しています。
public abstract class ComparableProduct
{
public ComparableProperty<decimal> Weight { get; set; }
public ComparableProperty<decimal> Width { get; set; }
public ComparableProperty<decimal> Height { get; set; }
public ComparableProperty<decimal> Depth { get; set; }
public bool IsBetterThan(ComparableProduct target){}
}
実際の製品は、プロパティを追加する Screen : ComparableProduct などの ComparableProduct から派生します。
ComparableProperty<decimal> Dimension { get; set; }
これは、すべて ComparableProduct から派生したプロパティ Keyboard、Screen、StorageDevice などを持つクラス Laptop を持つことができることを意味します。
これらには、次のような同等のプロパティがあります。
public abstract class ComparableProperty<T> where T : IComparable<T>
{
T Value { get; set; }
public ComparisonType ComparisonType { get; set; }
public bool IsBetterThan(T target)
{
if(ComparisonType == ComparisonType.GreaterThan)
return Value.CompareTo(target) >= 0;
return Value.CompareTo(target) <= 0;
}
public bool IsBetterThan(IEnumerable<T> targets)
{
foreach(var target in targets)
{
if (ComparisonType == ComparisonType.SmallerThan && Value.CompareTo(target) >= 0)
return false;
if (ComparisonType == ComparisonType.GreaterThan && Value.CompareTo(target) <= 0)
return false;
}
return true;
}
}
私はこれらをテストしていませんが、すべてのロジックで動作するはずです。私が抱えている問題は... ComparableProduct の IsBetterThan メソッドにあります。期待される機能は、最上位クラス (ラップトップなど) で、その ComparableProduct プロパティを介してループされ、他のコピーに対して IsBetterThan が呼び出され、サブプロパティをループすることです...さらに、すべての ComparableProduct ComparableProperty プロパティは IsBetterThan でチェックされます。他のクラスの同等の値で。
とにかく、ここに私が持っているものがあります。私が抱えている問題はすぐにわかります。
public bool IsBetterThan(ComparableProduct target)
{
foreach(var property in GetType().GetProperties().Where(x => x.PropertyType == typeof(ComparableProduct)))
{
var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as ComparableProduct;
var local = property.GetValue(this, null) as ComparableProduct;
if(local != null && !local.IsBetterThan(compareTo))
return false;
}
foreach(var property in GetType().GetProperties().Where(x => x.PropertyType == typeof(ComparableProperty<>)))
{
var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as ComparableProperty<>;
var local = property.GetValue(this, null) as ComparableProperty<>;
if(local != null && !local.IsBetterThan(compareTo))
return false;
}
}
ご覧のとおり、これを ComparableProperty<> にキャストしようとしています。つまり、ジェネリック型がありません。ただし、関連するプロパティのジェネリック型を取得する方法がよくわかりません。
あと、もっといい方法があれば… 出来る限りのコツは参考にさせて頂きますが、思いついた前半のまともなやり方です。
編集:
話すのが早すぎた。ComparableProduct の IsBetterThan のプロパティを次のように列挙しようとすると:
foreach(var property in GetType().GetProperties())
{
var t = property.GetType().GetInterfaces();
if (!property.GetType().GetInterfaces().Contains(typeof(IComparableProperty))) continue;
var compareTo = target.GetType().GetProperty(property.Name).GetValue(target, null) as IComparableProperty;
var local = property.GetValue(this, null) as IComparableProperty;
if (local == null) continue;
if(!local.IsBetterThan(compareTo))
return false;
}
次に、インターフェイスで IComparableProperty が見つからないようです。私はそれを含む可能性のある主要なメソッドを調べました...しかし、含まれている唯一のインターフェイスは、ICustomAttributeProvider、_MemberInfo、_PropertyInfo、および ISerializable です。
編集2:
文字列比較にフォールバックすることでこれを解決しました
if (property.PropertyType.Name != "ComparableProperty`1") continue;
T を ComparableProperty に変更し、IEnumerable を IEnumerable> に変更すると、比較全体が完全に機能します。