【问题标题】:How to .Dump() XNode as a regular object with properties in LINQPad?如何将 .Dump() XNode 作为具有 LINQPad 属性的常规对象?
【发布时间】:2018-09-28 17:29:20
【问题描述】:

通常,LINQPad 中的.Dump() 扩展方法将XNode 及其派生类实例显示为呈现的XML 片段。有时在开发代码时,我更愿意查看对象的实际属性,以与其他类型相同的表格形式显示,例如显示节点的名称、值、FirstAttribute 和 whatsnot 属性及其.ToString() 的表格值或可交互扩展的子对象集合。总而言之,就好像 XNode 根本没有经过特殊处理一样。

我正在通过转储单个属性来解决这个问题,但这很乏味。

This answer 建议编写自定义扩展代码来为另一种类型(即 IEnumerable)实现类似的效果,但它似乎比我正在处理的情况更窄更罕见。

是否有一种开箱即用的方式来做我想做的事?

【问题讨论】:

    标签: linqpad


    【解决方案1】:

    LINQPad 支持为类型自定义 Dump。使用一些扩展方法,您可以将类型转换为ExpandoObjects,然后将它们与属性一起输出。

    在我的扩展中,在MyExtensions 类之后,添加一个顶级方法:

    static object ToDump(object obj) {
        if (obj is XObject x)
            return x.ToExpando();
        else
            return obj;
    }
    

    MyExtensions 类中,添加以下扩展方法。我已经有 object->Dictionary 转换为匿名对象的方法,所以我使用了这些方法,但你可以将它们组合起来在 object 上创建一个 ToExpando

    public static ExpandoObject ToExpando(this object obj) => obj.ToDictionary().ToExpando();
    
    public static IDictionary<string, object> ToDictionary(this object obj) {
        if (obj is IDictionary<string, object> id)
            return id;
        else {
            var dictAnsObj = new Dictionary<string, object>();
    
            foreach (var prop in obj.GetType().GetPropertiesOrFields()) {
                try {
                    dictAnsObj.Add(prop.Name, prop.GetValue(obj));
                }
                catch (Exception ex) {
                    dictAnsObj.Add(prop.Name, ex);
                }
            }
    
            return dictAnsObj;
        }
    }
    
    public static ExpandoObject ToExpando(this IDictionary<string, object> objDict) {
        var e = new ExpandoObject();
        var di = (IDictionary<string, object>)e;
    
        foreach (var kvp in objDict)
            di.Add(kvp);
    
        return e;
    }
    

    您还需要这个Type 扩展:

    // ***
    // *** Type Extensions
    // ***
    public static List<MemberInfo> GetPropertiesOrFields(this Type t, BindingFlags bf = BindingFlags.Public | BindingFlags.Instance) =>
        t.GetMembers(bf).Where(mi => mi.MemberType == MemberTypes.Field | mi.MemberType == MemberTypes.Property).ToList();
    

    如果您可以仅以类格式显示顶级对象,则可以在需要时使用此扩展方法:

    public static T DumpAs<T, NewT>(this T obj, Func<T, NewT> castFn, string description = null) {
        if (description != null)
            castFn(obj).Dump(description);
        else
            castFn(obj).Dump();
    
        return obj;
    }
    

    例如,

    XElement xn;
    xn.DumpAs(x => x.ToExpando());
    

    否则,您将不得不注释掉 ToDump 方法或使用流利的方法做一些棘手的事情来打开和关闭它。

    【讨论】:

      【解决方案2】:

      此答案取决于先前的答案,但将其扩展为在需要时使用替代扩展方法和 ToDump 方法将XObjects 作为类处理。它使用与我之前的答案相同的扩展名。

      MyExtensions 类中,添加新类型的转储和bool 以跟踪状态:

      public static bool bDumpAsClass = false;
      
      public static object DumpAsClass(this object input, string descr = null) {
          bDumpAsClass = true;
          if (descr != null)
              input.Dump(descr);
          else
              input.Dump();
          bDumpAsClass = false;
          return input;
      }
      

      MyExtensions 类之外,添加一个使用boolToDump 方法:

      static object ToDump(object obj) {
          if (MyExtensions.bDumpAsClass) {
              if (obj is XObject x)
                  return x.ToExpando();
          }
      
          return obj;
      }
      

      然后,当您想将XObject 或后代转储为类时,您可以只使用DumpAsClass 而不是Dump,同时扩展任何成员。

      显然,当bDumpAsClass 为真时,您可以扩展处理的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        相关资源
        最近更新 更多