【发布时间】:2016-03-22 13:41:22
【问题描述】:
这是 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
其中很大一部分是为了使库尽可能轻松,我觉得必须指定类型有点失败。
有中间立场吗?我可以从接受的答案中获得更清晰、无反射的代码,并具有原始类型推断强度吗?
【问题讨论】:
-
如何在编译时知道要比较的属性 (
int Value),但只在运行时知道要比较的类?这似乎是一种脱节。似乎您可以提前构建可比较的类,而不是在运行时插入其信息。另外,必须进行所有类型检查是丑陋的。也许这是无法避免的,但是哎呀。我希望你能让这个更具体。为什么需要比较不同的类? -
@ErikE
[Left|Right]Comparable和Comparable是库类。Bar和Baz只是用户代码的示例。
标签: c# generics type-inference