【发布时间】:2021-04-16 22:09:33
【问题描述】:
有没有办法获得给定类型的默认比较器,其中类型是可变的并且仅在运行时才知道?考虑以下几点:
var RT = typeof(string);
var comparer = EqualityComparer<RT>.Default;
这显然不能编译,但如果编译了,comparer 的值应该等于 EqualityComparer<string>.Default 的值
我能想到的唯一方法是制作一个“盒装”比较器,您可以通过反射调用它(见下文)。这行得通,但它很麻烦。有没有更好的方法来做到这一点?
澄清一下,由于反思,这不是一个好主意,但我为什么需要它?
所讨论的算法是大型旧版搜索 API 的一部分。消费者将对象列表(例如,List<Person>)传递给 API,在内部创建类型特定的索引(使用反射),以便调用者可以搜索该对象中的任何字段(例如,可能是姓氏)。这通常不是必需的,但在我正在服务的用例中,我们正在搜索非常大的集合与其他非常大的集合。为此目的,数据库存储过程可能更好。但现在我需要修补这个遗留 API 以支持用户定义的比较算法,并且还支持用户选择不提供任何比较算法的情况,我只知道运行时类型RT。
// Example usage
// Assume "RT" is a Type known only at runtime (e.g., typeof(string))
var box = typeof(BoxedComparer<>);
var generic = box.MakeGenericType(RT);
var specific = (IBoxedComparer) Activator.CreateInstance(generic);
// Now with specific you can get the equality comparer for the runtime type (RT)
var comparer = specific.GetEqualityComparer();
public interface IBoxedComparer
{
// You need the interface to allow a "typeless" cast
EqualityComparer GetEqualityComparer()
}
public BoxedComparer<T> : IBoxedComparer
{
public EqualityComparer GetEqualityComparer() { return EqualityComparer<T>.Default; }
}
【问题讨论】:
-
你为什么要这样做?
-
从 EqualityComparer 获得的任何性能都可能因反射开销而丢失。
-
另外,您的示例无法编译
-
根据您存储对象的方式,您可以通过将委托传递给
Compare()来加快运行时间,但您仍然需要反射来获得它。 -
正如其他人所说,不建议为此使用反射。 (你打算如何实际使用
var comparer?更多反射?)FWIW,如果你继续沿着反射路径,你不需要额外的'BoxedComparer'类。这是一个单行代码:var comparer = typeof(EqualityComparer<>).MakeGenericType(RT).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetValue(null);(需要使用System.Collections.Generic和System.Reflection的语句。)
标签: c# .net-4.7.2