これはthis questionの拡張であり、その特定のケースでうまくいきます。タイプ逆制約付きジェネリックの間の推論
私の実際のコードはより次のようになります。
public abstract class BaseComparable<TLeft, TRight>
{ }
public class LeftComparable<TLeft, TRight> : BaseComparable<TLeft, TRight> where TLeft : IComparable<TRight>
{
public LeftComparable(TLeft value) { }
}
public class RightComparable<TLeft, TRight> : BaseComparable<TLeft, TRight> where TRight : IComparable<TLeft>
{
public RightComparable(TLeft value) { }
}
あなたは私が掲示するものと同等の反射コードを使用する場合、それは素晴らしい作品:
public static BaseComparable<TLeft, TRight> AsComparableFor<TLeft, TRight>(this TLeft left, TRight right)
{
if (left is IComparable<TRight>)
{
var constructor =
typeof(LeftComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
if (right is IComparable<TLeft>)
{
var constructor =
typeof(RightComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
throw new ArgumentException();
}
次にあなたが
class Baz
{
public int Value { get; set; }
}
class Bar : IComparable<Baz>
{
public int Value { get; set; }
int IComparable<Baz>.CompareTo(Baz other)
{
return Value.CompareTo(other.Value);
}
}
// ....
var bar = new Bar { Value = 1 };
var baz = new Baz { Value = 1 };
var compBaz = baz.AsComparableFor(bar);
var compBar = bar.AsComparableFor(baz);
を言うことができます
ファンタスティックな型推論は、期待どおりに機能します。
上記受け入れ答えからの適応は、しかし、
public static class Comparable
{
public static BaseComparable<TLeft, TRight>
AsComparableFor<TLeft, TRight>(this IComparable<TRight> left, TRight right)
where TLeft : IComparable<TRight>
{
if (left is TLeft)
{
if (left is IComparable<TRight>)
{
return new LeftComparable<TLeft, TRight>((TLeft)left);
}
}
throw new InvalidCastException();
}
public static BaseComparable<TLeft, TRight>
AsComparableFor<TLeft, TRight>(this TLeft left, IComparable<TLeft> right)
where TRight : IComparable<TLeft>
{
if (left is TLeft)
{
if (right is IComparable<TLeft>)
{
return new RightComparable<TLeft, TRight>((TLeft)left);
}
}
throw new InvalidCastException();
}
}
は、明示的に型引数を述べるために、あなたが必要です:この
//bar.AsComparableFor(baz);
//baz.AsComparableFor(bar); //Does not compile
bar.AsComparableFor<Bar, Baz>(baz);
baz.AsComparableFor<Baz, Bar>(bar); // Does compile
大部分はとしてライブラリはよう無痛作ることでした可能であり、タイプを指定しなければならないと感じるのは幾分敗北します。
中間地はありますか?私は、元の型推論の強さと受け入れられた答えからクリーナー、反射のないコードを得ることができますか?
編集:full code can be found in this gist.
比較するプロパティ( 'int Value')をコンパイル時に知ることができますが、どのクラスを比較するのが実行時に分かりますか?これは切断のようです。実行時に情報を挿入するのではなく、あらかじめ同等のクラスを構築できるようです。さらに、すべての型チェックを行うことは醜いです。おそらく、それは避けられないものですが、大変です。私はあなたがこれをさらに具体的にすることができたらいいと思う。異なるクラスを比較する必要性はなぜですか? – ErikE
@ErikE '[Left | Right] ComparableとComparableはライブラリクラスです。 'Bar'と' Baz'は、ユーザーコードの例です。 – RoadieRich