使用 lambda 表达式的嵌套集合创建对象图

2024-02-14

我对利用 lambda 表达式创建属性选择器树感兴趣。

使用场景是,我们有一些代码对对象图进行一些递归反射,为了限制递归的范围,我们目前使用 Attributes 来标记应该遍历哪些属性。即获取对象的所有修饰属性,如果该属性是具有修饰属性的引用类型,则也对每个属性重复。

使用属性的限制是您只能将它们放置在您控制源的类型上。 lambda 表达式树允许在任意类型的公共成员上定义范围。

如果有一种简写方式来定义这些表达式,它会反映对象图的结构,这会很方便。

最终,我希望有这样的东西:

Selector<MyType> selector = new [] {
        (t => Property1),
        (t => Property2)
        {
                p => NestedProperty1,
                p => NestedProperty2
        }
};

现在,我能做的最好的事情就是为每个节点明确声明一个实例,如下所示:

var selector = new Selector<MyType>()
{
    new SelectorNode<MyType, Property1Type>(t => Property1),
    new SelectorNode<MyType, Property2Type>(t => Property2)
    {
        new SelectorNode<Property2Type, NestedProperty1Type>(p => NestedProperty1),
        new SelectorNode<Property2Type, NestedProperty2Type>(p => NestedProperty2)
    },
};

这段代码没有任何问题,但是您必须显式写出每个节点的类型参数,因为编译器无法推断类型参数。这是一种痛苦。而且丑陋。我已经看到了一些令人难以置信的语法糖,并且确信一定有更好的方法。

由于我对“更高”的 C# 概念(例如动力学、协/逆变泛型和表达式树)缺乏理解,我想我应该把这个问题提出来,看看是否有任何专家知道实现这一目标的方法(或者类似的东西)它?)


作为参考,这些是声明Selector and SelectorNode实现我在帖子中描述的结构的类:

public interface ISelectorNode<T> {}

public class Selector<T>: List<ISelectorNode<T>>{}

public class SelectorNode<T, TOut>: List<ISelectorNode<TOut>>, ISelectorNode<T> 
{
    public SelectorNode(Expression<Func<T, TOut>> select) {}
}

//Examples of Usage below

public class Dummy
{
    public ChildDummy Child { get; set; }
}

public class ChildDummy
{
    public string FakeProperty { get; set; }
}

public class Usage
{
    public Usage()
    {
        var selector = new Selector<Dummy>
        {
            new SelectorNode<Dummy, ChildDummy>(m => m.Child)
            {
                new SelectorNode<ChildDummy, string>(m => m.FakeProperty)
            }
        };
    }
}

为了扩展 nawal 的答案而进行了编辑:

利用 C# 的集合初始值设定项语法,我们可以获得如下代码:

var selector = new Selector<Dummy>
  {
      (m => m.Child),
      {dummy => dummy.Child, 
          c => c.FakeProperty,
          c => c.FakeProperty                    
      }
  };

如果我们的 SelectorNode 类的 Add 方法如下所示:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector, params Expression<Func<TOut, object>>[] children)
    {
        return SelectorNode<T, T, TOut>.Add(this, this, selector);
    }
}

必须有一种方法来利用这种语法!


编辑:我的以下答案不可原谅地没有回答这个问题。我不知怎么读错了。我将提供另一个实际上可以完成这项工作的答案。保持这个答案开放,因为它可能会帮助将来的人解决相关问题。


您可以通过流畅的界面进行管理,但可能不适合您。

让你的选择器类像这样:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        return SelectorNode<T, TOut>.Add(this, selector);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    //move this common functionality to a third static class if it warrants.
    internal static SelectorNode<T, TOut> Add(List<ISelectorNode<T>> list, Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        list.Add(node);
        return node;
    }



    SelectorNode(Expression<Func<T, TOut>> selector) //unhide if you want it.
    {

    }



    public SelectorNode<TOut, TNextOut> Add<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return SelectorNode<TOut, TNextOut>.Add(this, selector);
    }
}

现在您可以致电:

var selector = new Selector<Dummy>();
selector.Add(m => m.Child).Add(m => m.FakeProperty); //just chain the rest..

我个人认为这比您在问题中的方法更具可读性,但并不那么直观或令人讨厌:)我认为您不能将其放在一行中(遗憾的是:(),但可能有一种困难的方法。

Update:

一行:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        return SelectorNode<T, T, TOut>.Add(this, this, selector);
    }
}



public class SelectorNode<S, T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    //move this common functionality to a third static class if it warrants.
    internal static SelectorNode<S, T, TOut> Add(Selector<S> parent, List<ISelectorNode<T>> list, 
                                                 Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<S, T, TOut>(parent, selector);
        list.Add(node);
        return node;
    }



    Selector<S> parent;

    SelectorNode(Selector<S> parent, Expression<Func<T, TOut>> selector) //unhide if you want it.
    {
        this.parent = parent;
    }



    public SelectorNode<S, TOut, TNextOut> Add<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return SelectorNode<S, TOut, TNextOut>.Add(parent, this, selector);
    }

    public Selector<S> Finish()
    {
        return parent;
    }
}

Usage:

var selector = new Selector<Dummy>().Add(m => m.Child).Add(m => m.FakeProperty).Finish();

//or the earlier

var selector = new Selector<Dummy>();
selector.Add(m => m.Child).Add(m => m.FakeProperty); //just chain the rest, no need of Finish

第一种方法的优点:

  1. Simpler

  2. 不改变现有的定义(SelectorNode)

第二个优点:

  1. 提供更干净的通话。

这两种方法的一个小缺点可能是现在您有一个内部静态方法Add用于共享通用功能,这些功能在这两个选择器类之外没有任何意义,但我想这是可以接受的。您可以删除该方法和重复的代码(或者困难的方法,嵌套SelectorNode inside Selector并向外界隐藏实施如果SelectorNode在外面没有任何意义Selector班级。或者更糟糕的是让它受到保护并从另一个类继承一个类)

建议:您可能很可能想去作品遗产与你的方式List<T>s。您的类名称(选择器)不会给出其下面的集合的概念。顺便说一句,好问题!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 lambda 表达式的嵌套集合创建对象图 的相关文章

随机推荐

  • 如何在 Android 中呈现泰米尔语 unicode

    Okay 所以我的问题是我有一个 XML 泰米尔语 unicode feed 我想获取它并将其显示在 Android 应用程序中 当我尝试执行此操作时 由于 Android 没有对泰米尔语的本机支持 因此必须使用自定义字体 但随后问题就出现
  • SQL Server 2005 T-SQL 中的 Base64 编码

    我想编写一个 T SQL 查询 将字符串编码为 Base64 字符串 令人惊讶的是 我找不到任何用于执行 Base64 编码的本机 T SQL 函数 是否存在本机函数 如果没有 在 T SQL 中进行 Base64 编码的最佳方法是什么 我
  • UIImage调整大小(缩放比例)[重复]

    这个问题在这里已经有答案了 可能的重复 调整 UIImage 的纵横比 https stackoverflow com questions 1703100 resize uiimage with aspect ratio 下面的代码完美地调
  • Git 因 100% cpu 使用而挂起(这是磁盘问题)

    有一些操作挂在我的存储库之一上 git gc 在 计数对象 7409 处以 100 使用率挂起 当我启动 gitk 时 它会启动此命令 该命令也会因 100 CPU 使用率而挂起 git log no color z pretty raw
  • EPPlus“System.OutOfMemoryException”

    我正在尝试使用打开 38MB Excel 文件EPPlus v4 0 我可以将它传递给Excel包变量 但是当我尝试从该变量获取工作簿时 它会导致我出现 系统内存不足异常 这是我的代码 Dim temppath Path GetTempPa
  • 如何使工具栏后退按钮居中?

    我在尝试将后退按钮置于支持工具栏中央时遇到问题 我在 ActionBarActivity 中使用它
  • 在 CentOS 中使用 /etc/resolv.conf 解析 AD 域

    我已使用 Realm 配置 SSSD 以使用 AD 凭据登录 centOS VM 请参考设置here https stackoverflow com questions 63705156 sssd integration with micr
  • 如何用Java编写UTF-8文件?

    我有一些当前代码 问题是它创建了一个 1252 代码页文件 我想强制它创建一个 UTF 8 文件 任何人都可以帮助我使用这段代码 正如我所说 它目前有效 但我需要强制保存在 utf 上 我可以传递参数或其他东西吗 这就是我所拥有的 非常感谢
  • 在 Windows 中使用 Python 获取日期格式

    在给我的作业示例代码中 出现了这一行 date format locale nl langinfo locale D FMT 但在 Windows 中 该行返回以下错误 File C Users Shadark Dropbox IHM P3
  • 解释 OpenGL ES 背景图像的工作原理

    有人可以解释一下如何在 OpenGL ES 视图上渲染背景图像吗 从设置 OpenGL 环境的基础知识开始 我是 OpenGL 的新手 I m seeing https stackoverflow com questions 3387132
  • 如何使用 Firefox 插件从硬盘读取/写入文件?

    是否可以开发一个可以从硬盘读取 写入文件的 Firefox 插件 我应该使用什么代码 它只是链接 Hypnos 和 ephemient 中提供的代码的复制 和组合 const Cc Ci require chrome create prop
  • 模拟标准输入 - python 3中的多行

    我是 python 新手 一直在使用 python 3 进行学习 我正在使用 python 的单元测试框架来测试我的代码 问题 我需要进行单元测试的函数以以下方式接受输入 def compare a b c input strip spli
  • PHP 中比较的可变位置

    下面两种情况哪个更优化 if var value and if value var 抱歉 如果这与另一个问题重复 但我无法用谷歌搜索出答案 Thanks UPDATE 这称为尤达条件 更多信息here http wiert me 2010
  • 为什么 DRF 可浏览 API 对每个实际请求的多个请求类型运行权限检查?

    我有一个简单的 DRF 列表视图 想要编写一些与以下内容相关的权限POST要求 这导致了错误GET发出了请求 这让我意识到我的权限类在未提交的请求上被多次调用 这是我的文件 权限 py class IsDummy permissions B
  • django 形成 MultipleChoiceField 在保存时恢复为原始值

    我编写了一个自定义 MultipleChoiceField 我一切正常 但是当我提交表单时 即使表单验证正常 所选值也会返回原始选择 我的代码看起来像这样 class ProgrammeField forms MultipleChoiceF
  • 连接池到底是什么?

    我听说过连接池这个术语 并通过谷歌搜索寻找一些参考资料 但不知道何时使用它 我什么时候应该考虑使用 连接池 有什么优点和 连接池的缺点 任何建议 这个想法是 您不会打开和关闭与数据库的单个连接 而是创建一个打开连接的 池 然后重用它们 一旦
  • Cocoa App webview未加载请求

    我已经使用 webview 加载 url 但它没有加载 我已经尝试使用 wkwebview 进行相同的操作 但无法加载网址 我已经做了以下 导入WebKit Info plist 允许任意负载 是 允许任意加载网页内容 是 LOG dnss
  • 使用智能指针实现容器

    好的 所以每个人都知道应该像瘟疫一样避免原始指针并更喜欢智能指针 但是这个建议在实现容器时适用吗 这就是我想要实现的目标 template
  • 在 Msys 上安装 Pip

    我使用 Python 3 5 2 和 Msys 构建了一个简单的 PyGTK 应用程序 但我需要一些默认安装中没有的模块 尽管我可以使用setup py install为了得到它们我宁愿使用pip 我环顾四周发现this https sou
  • 使用 lambda 表达式的嵌套集合创建对象图

    我对利用 lambda 表达式创建属性选择器树感兴趣 使用场景是 我们有一些代码对对象图进行一些递归反射 为了限制递归的范围 我们目前使用 Attributes 来标记应该遍历哪些属性 即获取对象的所有修饰属性 如果该属性是具有修饰属性的引