这是来自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
这很大一部分是为了让图书馆尽可能轻松,我觉得必须在某种程度上指明类型的失败。
有中间地带吗?我可以使用原始类型推断强度从已接受的答案中获取更清晰,无反射的代码吗?
答案 0 :(得分:1)
我是否可以使用原始类型推断强度从已接受的答案中获取更清晰,无反射的代码?
你做不到。实际上接受的答案并不好,因为它涉及价值型拳击。
所以再一次,你无法避免反思。你可以做的是通过使用与EqualityComparer<T>.Default
implementation,Comparer<T>.Default
等相同的技术来最小化反射。唯一的区别是,而不是创建一个单例实例,我们将创建一个单例工厂委托:
public abstract class BaseComparable<TLeft, TRight>
{
public static readonly Func<TLeft, BaseComparable<TLeft, TRight>> Factory = CreateFactory();
private static Func<TLeft, BaseComparable<TLeft, TRight>> CreateFactory()
{
Type genericTypeDefinition;
if (typeof(IComparable<TRight>).IsAssignableFrom(typeof(TLeft)))
genericTypeDefinition = typeof(LeftComparable<,>);
else if (typeof(IComparable<TLeft>).IsAssignableFrom(typeof(TRight)))
genericTypeDefinition = typeof(RightComparable<,>);
else
throw new ArgumentException();
var parameter = Expression.Parameter(typeof(TLeft), "value");
var body = Expression.New(genericTypeDefinition
.MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) }), parameter);
var lambda = Expression.Lambda<Func<TLeft, BaseComparable<TLeft, TRight>>>(body, parameter);
return lambda.Compile();
}
}
public static class BaseComparable
{
public static BaseComparable<TLeft, TRight> AsComparableFor<TLeft, TRight>(this TLeft left, TRight right)
{
return BaseComparable<TLeft, TRight>.Factory(left);
}
}