C# 如何编写支持对象初始值设定项的自定义DynamicObject类

C# 如何编写支持对象初始值设定项的自定义DynamicObject类,c#,linq,dynamic,object-initializers,C#,Linq,Dynamic,Object Initializers,在的文档中,有一个DynamicDictionary示例,它允许您使用字典,就像它是一个具有属性的类一样 以下是课程(为简洁起见稍作修改): 问题 这可能吗 如果是,如何进行 DynamicObject提供了,这是针对这种情况的,但在C#中不可用 我看到了一些解决方法: 创建一个动态工厂类。当您使用命名参数调用其Create()方法时,它会将其传递到字典: class DynamicDictionaryFactory : DynamicObject { public override b

在的文档中,有一个
DynamicDictionary
示例,它允许您使用字典,就像它是一个具有属性的类一样

以下是课程(为简洁起见稍作修改):

问题

  • 这可能吗
  • 如果是,如何进行

  • DynamicObject
    提供了,这是针对这种情况的,但在C#中不可用

    我看到了一些解决方法:

  • 创建一个动态工厂类。当您使用命名参数调用其
    Create()
    方法时,它会将其传递到字典:

    class DynamicDictionaryFactory : DynamicObject
    {
        public override bool TryInvokeMember(
            InvokeMemberBinder binder, object[] args, out object result)
        {
            if (binder.Name == "Create")
            {
                // use binder.CallInfo.ArgumentNames and args
                // to create the dynamic dictionary
                result = …;
                return true;
            }
    
            return base.TryInvokeMember(binder, args, out result);
        }
    }
    
    …
    
    dynamic factory = new DynamicDictionaryFactory();
    
    dynamic dict = factory.Create(Id: 42);
    
  • 使用非动态集合初始值设定项。这意味着在代码中将属性名称作为字符串:

    // has to implement IEnumerable, so that collection initializer works
    class DynamicDictionary
        : DynamicObject, IEnumerable<KeyValuePair<string, object>>
    {
        public void Add(string name, object value)
        {
            m_dictionary.Add(name, value);
        }
    
        // IEnumerable implmentation and actual DynamicDictionary code here
    }
    
    …
    
    dynamic dict = new DynamicDictionary { { "Id", 42 } };
    

  • 使用开源的ImpromptuInterface(通过nuget),它有一个。这使您可以执行一些接近初始化语法的操作。特别是在包含
    ImpromptuInterface.Dynamic之后

       var result = Enumerable.Range(1, 5).Select(i => Build<DynamicDictionary>.NewObject
        (
            Id: i,
            Foo: "Foo",
            Bar: 2
        ));
    
    var result=Enumerable.Range(1,5)。选择(i=>Build.NewObject
    (
    Id:我,
    福:“福”,
    酒吧:2间
    ));
    

    该语法页面上还列出了其他选项,如果您删除
    ,它将使用本质上相同的
    即兴词典。您也可以查看构建语法的

    事实证明,我能够通过使用Linq的内置
    ToDictionary()
    方法解决我的问题

    例如:

    public Test()
    {
        var data = Enumerable.Range(1, 5).Select(i => new
        {
            Id = i,
            Foo = "Foo",
            Bar = 2
        });
        var result = data
            .Select(d => d.GetType().GetProperties()
                .Select(p => new { Name = p.Name, Value = p.GetValue(pd, null) })
                .ToDictionary(
                    pair => pair.Name,
                    pair => pair.Value == null ? string.Empty : pair.Value.ToString()));
    }
    

    当我看到这样的嵌入式语言模式时,我倾向于使用扩展方法,因此我可以编写以下代码来实现我的目标:

    public Test()
    {
        var data = Enumerable.Range(1, 5).Select(i => new
        {
            Id = i,
            Foo = "Foo",
            Bar = 2
        }.AsDynamicDictionary());
    }
    
    然后,我将使用代码定义扩展方法,以将任何
    对象
    (包括匿名键入的对象)转换为
    DynamicDictionary

    public static class DynamicDictionaryExtensions
    {
        public static DynamicDictionary AsDynamicDictionary(this object data)
        {
            if (data == null) throw new ArgumentNullException("data");
            return new DynamicDictionary(
                   data.GetType().GetProperties()
                   .Where(p => p. && p.CanRead)
                   .Select(p => new {Name: p.Name, Value: p.GetValue(data, null)})
                   .ToDictionary(p => p.Name, p => p.Value)
            );
        }
    }
    

    您必须在
    DynamicDictionary
    中实现构造函数才能接收
    IDictionary
    ,但这是小菜一碟。

    对象初始值设定项不适用于dynamicobjects@Magnus,从技术上讲,它可以处理动态对象,但只能以非动态方式。因此,如果动态对象具有非动态
    Id
    属性,则可以使用对象初始值设定项。但这无助于回答这个问题。没错,对于“正常”属性,它可以正常工作。我想你可以添加一个构造函数,它接受
    IEnumerable
    并使用它来创建字典p、 CanRead
    您似乎遗漏了一些内容。
    public Test()
    {
        var data = Enumerable.Range(1, 5).Select(i => new
        {
            Id = i,
            Foo = "Foo",
            Bar = 2
        });
        var result = data
            .Select(d => d.GetType().GetProperties()
                .Select(p => new { Name = p.Name, Value = p.GetValue(pd, null) })
                .ToDictionary(
                    pair => pair.Name,
                    pair => pair.Value == null ? string.Empty : pair.Value.ToString()));
    }
    
    public Test()
    {
        var data = Enumerable.Range(1, 5).Select(i => new
        {
            Id = i,
            Foo = "Foo",
            Bar = 2
        }.AsDynamicDictionary());
    }
    
    public static class DynamicDictionaryExtensions
    {
        public static DynamicDictionary AsDynamicDictionary(this object data)
        {
            if (data == null) throw new ArgumentNullException("data");
            return new DynamicDictionary(
                   data.GetType().GetProperties()
                   .Where(p => p. && p.CanRead)
                   .Select(p => new {Name: p.Name, Value: p.GetValue(data, null)})
                   .ToDictionary(p => p.Name, p => p.Value)
            );
        }
    }