测量类型之间的关系继承距离

时间:2015-04-20 11:04:10

标签: c# asp.net .net inheritance controls

有谁知道我是如何(或者如果有现有算法)测量两种.NET类型之间的关系距离?

我指的是从对象A到对象B所需的分层树中的“步骤”数。

例如,如果对象A是Button,而对象B是LinkBut​​ton,则会有2个步骤,Button - > WebControl - > LinkBut​​ton的。我是否需要创建自己的静态继承树并使用路径查找算法,还是有一种方法可以动态查看.NET的继承结构来计算两个对象之间的距离?

3 个答案:

答案 0 :(得分:1)

您可以使用Type.BaseType遍历继承路径。例如:

 public static int GetTypeDistance<T, B>(T t, B baseType)
 {
        if (t is B) // checking if t inherits baseType
        {
            int distance = 0;
            Type curType = t.GetType();

            while (curType != typeof(B) && curType != null)
            {
                distance++;
                curType = curType.BaseType;                  
            }
            return distance;
        }
        else { throw new Exception("..."); }            
}

答案 1 :(得分:1)

非通用方式(您也不必明确指定父/子):

private static int CalulateDistanceOneWay(Type firstType, Type secondType)
{
  var chain = new List<Type>();
  while (firstType != typeof(object))
  {
    chain.Add(firstType);
    firstType = firstType.BaseType;
  }

  return chain.IndexOf(secondType);
}

// returns -1 for invalid input, distance between types otherwise
public static int CalculateDistance(Type firstType, Type secondType)
{
  int result = CalulateDistanceOneWay(firstType, secondType);
  if (result >= 0)
  {
    return result;
  }

  return CalulateDistanceOneWay(secondType, firstType);
}

编辑:更新计算表兄弟:

public class DistanceResult
{
  public Type SharedAncestor { get; private set; }
  public int FirstTypeDistance { get; private set; }
  public int SecondTypeDistance { get; private set; }

  public DistanceResult(Type sharedAncestor, int firstTypeDistance, int secondTypeDistance)
  {
    SharedAncestor = sharedAncestor;
    FirstTypeDistance = firstTypeDistance;
    SecondTypeDistance = secondTypeDistance;
  }
}

static DistanceResult CalculateDistance(Type firstType, Type secondType)
{
  var firstChain = new List<Type>();
  while (firstType != typeof(object))
  {
    firstChain.Add(firstType);
    firstType = firstType.BaseType;
  }
  firstChain.Add(typeof(object));

  var secondChain = new List<Type>();
  while(secondType != typeof(object))
  {
    secondChain.Add(secondType);
    secondType = secondType.BaseType;
  }
  secondChain.Add(typeof(object));

  for(var i = 0; i < secondChain.Count; i++)
  {
    var type = secondChain[i];
    int index = firstChain.IndexOf(type);
    if (index >= 0)
    {
      return new DistanceResult(firstChain[index], index, i);
    }
  }

  return null;
}

答案 2 :(得分:0)

根据Ondrej和Bényi的答案,这里有两种扩展方法来计算从特定类型到其(间接)基类类型或由其实现的接口或其基类之一的距离。

用法示例:

Assert.AreEqual( 4, typeof( MultiDictionary<int, int> ).DistanceTo<IEnumerable>() );
Assert.AreEqual( 4, typeof( MultiDictionary<int, int> ).DistanceTo( typeof( IEnumerable ) );
Assert.AreEqual( 2, typeof( StringReader ).DistanceTo( typeof( IDisposable ) ) );

扩展方法:

public static class ExtensionsForType
{
    public static int DistanceTo( [CanBeNull] this Type current, [NotNull] Type target )
    {
        Contract.Requires<ArgumentNullException>( target != null );

        // `root` will point to the topmost type which is implementing
        // our `target` interface
        Type root = current;

        // search for topmost base type implementing `target` interface type
        // or for the `target` base class type itself
        int distance = 0;
        while ( current != null && ( target.IsInterface
            ? current.GetInterfaces().Contains( target )
            : current != target ) )
        {
            root = current;
            current = current.BaseType;
            distance++;
        }

        // probably the `current` type does not even derive from / implement
        // the target type at all
        if ( current == null ) return -1;

        // if it's not an interface then we've found it in one of the base classes
        if ( !target.IsInterface ) return distance;

        // go one step back, because 'current' does not implement
        // our target interface anymore
        distance--;

        // iterate interface "derivations" while the target interface is still
        // in the list of implemented interfaces
        Type[] interfaces = root.GetInterfaces();
        while ( interfaces.Contains( target ) )
        {
            interfaces = interfaces.SelectMany( i => i.GetInterfaces() ).ToArray();
            distance++;
        }

        return distance;
    }

    public static int DistanceTo<T>( [CanBeNull] this Type current )
    {
        return current.DistanceTo( typeof( T ) );
    }
}