gpt4 book ai didi

c# - 如何通过继承对类进行排序?

转载 作者:行者123 更新时间:2023-11-30 23:12:32 37 4
gpt4 key购买 nike

我正在使用反射来检索可用类的列表,并且我想将输入对象调整为匹配的最特定类;即我想做类似的事情:

RawData input = new RawData() { ... };
Type targetAdapter = AdapterSelector.SelectAdapterFor(input);
AdapterSelector.TryGetAdaptMethod(targetAdapter, out Func<RawData, Adapter> fAdapt);
Adapter adapted = fAdapt(input);

每个适用的类都有以下签名:

public class Adapter
{
public static Adapter Adapt(RawData input) { ... }
public static bool Matches(RawData input) { ... }
}

可以使用反射1按如下方式检索具有所需方法的类列表:

public partial class AdapterSelector
{
public static IEnumerable<Type> GetApplicableAdapterTypes()
{
IEnumerable<Type> allTypes = typeof(AdapterSelector).Assembly.GetTypes();
IEnumerable<Type> applicableTypes = from t in allTypes
where TryGetAdaptMethod(t, _) &&
TryGetMatchMethod(t, _)
select t;
return applicableTypes;
}

private static bool TryGetAdaptMethod(Type type, out Func<RawData, Adapter> adapt)
{
MethodInfo adaptMethod = type.GetMethod("Adapt", BindingFlags.Static|BindingFlags.Public, null, new Type[] { typeof(RawData) }, null);
if (adaptMethod != null)
{
adapt = (Func<RawData, Adapter>)Delegate.CreateDelegate(typeof(Func<RawData, Adapter>), null, adapterMethod);
return true;
}
else
{
adapt = null;
return false;
}
}

private static bool TryGetMatchMethod(Type type, out Func<RawData, bool> match)
{
MethodInfo matchMethod = type.GetMethod("Match", BindingFlags.Static|BindingFlags.Public, null, new Type[] { typeof(RawData) }, null);
if (matchMethod != null)
{
match = (Func<RawData, bool>)Delegate.CreateDelegate(typeof(Func<RawData, bool>), null, matchMethod);
return true;
}
else
{
match = null;
return false;
}
}
}

我假设我可以使用以下 IComparer<Type> 要订购此适配器列表:

public class TypeHierarchyComparer: IComparer<Type>
{
public int Compare(Type lhs, Type rhs)
{
if (rhs.IsSubclassOf(lhs))
{
return -1;
}
else if (lhs.IsSubclassOf(rhs))
{
return +1;
}
else
{
// Return arbitrary but fixed value for siblings, cousins, etc.
return lhs.FullName.CompareTo(rhs.FullName);
}
}
}

请注意,这是一种偏序:如果一种类型是另一种类型的子类,则该类型应排在2 后者之后。如果两种类型都不是另一种类型的子类,则顺序未定义。

通过这种排序,我希望适配器的以下层次结构能够正确排序3:

  • Adapter
    • N
    • F
    • H
    • I
    • K
      • E
      • G
      • L
      • M
      • Q
      • R
    • O
    • B
    • C
    • J
    • P
      • AA
      • AB
      • D
      • S
      • T

但是,结果:

AdapterSelector.GetApplicableAdapterTypes().OrderBy((x) => x, new TypeHierarchyComparer());

是:

Adapter , AA , AB , B , C , D , N , F , H , I , J , K , P , E , G , L , M , O , P , Q , R , S , T

顺序是否正确OP应在 AA 之前订购, AB , D , S , 和 TO应该在 B 之前, C , 和 J .看起来子类是在其父类之一之后排序的,但不一定在所有父类之后。

如何按特异性对类别进行排序? (即在所有父类之前/之后对子类进行排序)


1) 参见 Assembly.GetTypes() , Type.GetMethod(string, BindingFlags, Binder, Type[], ParameterModifier[]) , Can you get a Func<T> (or similar) from a MethodInfo object? , 和 Delegate.CreateDelegate(Type, object, methodInfo)

2) 我正在使用 Enumerable.OrderByDescending<TSource, TKey>(this IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) 让匹配器首先应用在列表的前面。

3) Visual Studio 的解决方案资源管理器显示的类层次结构。我不能透露适配器的名称,因此我使用了 AAT ,我保留了名称的字母顺序。

最佳答案

问题是你的任意排序规则太随意了。

而不是按类型名称排序(因此,比较 GB 会说 G 应该在 B 之后),您应该找到两个不相关类型的最接近的共同祖先。然后,您应该根据两种类型的共同祖先的直接后代应用排序。

因此,为了比较 GB ,您找到最接近的共同祖先 (Adapter),然后找到这两种类型的后代类型(KB),然后对那些执行任意排序规则类型。


类似这样的事情(不保证代码质量 :-)):

    public List<Type> Ancestors(Type any)
{
var result = new List<Type>();
result.Add(any);
while (any != typeof(object))
{
any = any.BaseType;
result.Insert(0, any);
}
return result;
}
public int Compare(Type lhs, Type rhs)
{
if (rhs.IsSubclassOf(lhs))
{
return -1;
}
else if (lhs.IsSubclassOf(rhs))
{
return +1;
}
else
{
var lAncs = Ancestors(lhs);
var rAncs = Ancestors(rhs);
int ix = 0;
while (lAncs[ix] == rAncs[ix])
{
ix++;
}
return lAncs[ix].FullName.CompareTo(rAncs[ix].FullName);
}
}

我认为这段代码不会偏离列表的末尾,因为如果其中一个列表已用完,则意味着其中一种类型实际上是另一种类型的祖先,所以之前的子类化规则应该已经解决了比较。

此外,您可能希望考虑使用 Dictionary<Type,List<Type>> 来“内存”祖先查找。 .

关于c# - 如何通过继承对类进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44044723/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com