這是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