C# DynamicObject和TrySetMember性能与ExpandooObject性能

C# DynamicObject和TrySetMember性能与ExpandooObject性能,c#,dynamic,expandoobject,dynamicobject,C#,Dynamic,Expandoobject,Dynamicobject,我正在使用DynamicObject的自定义实现,它非常适合我的应用程序,而不是遇到一些性能问题。dynamics会带来一些性能开销,但即使使用ExpandooObject,我也会看到显著的性能损失(数量级) 我不能使用ExpandooObject的原因是我想覆盖它的一些行为。我把这个问题归结为下面一个非常简单的例子 我的自定义ExpandoObject代码如下(简化为刚好足以显示问题的代码)-- 在TrySetMember方法中,只留下一个“returntrue;”,并且性能相同 如果我在Su

我正在使用DynamicObject的自定义实现,它非常适合我的应用程序,而不是遇到一些性能问题。dynamics会带来一些性能开销,但即使使用ExpandooObject,我也会看到显著的性能损失(数量级)

我不能使用ExpandooObject的原因是我想覆盖它的一些行为。我把这个问题归结为下面一个非常简单的例子

我的自定义ExpandoObject代码如下(简化为刚好足以显示问题的代码)--

在TrySetMember方法中,只留下一个“returntrue;”,并且性能相同

如果我在SuperExpando类中添加以下内容--

通过TryGetMember访问(读取)变量的性能问题是相同的,而直接读取字典可以提供合理的性能

有什么想法吗

-BJ Quinn

编辑:下面是完整的示例代码。只需创建一个表单并在其上放置一个运行go_Click事件的按钮,然后将项目设置为控制台应用程序。对我来说,在ExpandoObject中设置所有50个键需要约30毫秒,而SuperExpando至少需要约750毫秒

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Dynamic;

namespace test
{
    public partial class ExpandoTest : Form
    {
        public ExpandoTest()
        {
            InitializeComponent();
        }

        public class SuperExpando : DynamicObject
        {
            public Dictionary<string, object> dictionary = new Dictionary<string, object>();

            public override bool TrySetMember(SetMemberBinder binder, object value)
            {
                //dictionary[binder.Name] = value;
                return true;
            }
        }

        DateTime lasttime = DateTime.Now;

        public void outputtime(string label = "")
        {
            TimeSpan elapsedtime = DateTime.Now - lasttime;
            Double elapsedms = elapsedtime.TotalMilliseconds;
            Console.WriteLine(label + " : " + elapsedms.ToString());
            lasttime = DateTime.Now;
        }

        private void go_Click(object sender, EventArgs e)
        {
            outputtime("Time spent waiting on user");
            dynamic se = new SuperExpando();
            outputtime("Declared SuperExpando");
            se.test120 = 5;
            se.test121 = 5;
            se.test122 = 5;
            se.test123 = 5;
            se.test124 = 5;
            se.test125 = 5;
            se.test126 = 5;
            se.test127 = 5;
            se.test128 = 5;
            se.test129 = 5;
            se.test130 = 5;
            se.test131 = 5;
            se.test132 = 5;
            se.test133 = 5;
            se.test134 = 5;
            se.test135 = 5;
            se.test136 = 5;
            se.test137 = 5;
            se.test138 = 5;
            se.test139 = 5;
            se.test140 = 5;
            se.test141 = 5;
            se.test142 = 5;
            se.test143 = 5;
            se.test144 = 5;
            se.test145 = 5;
            se.test146 = 5;
            se.test147 = 5;
            se.test148 = 5;
            se.test149 = 5;
            se.test150 = 5;
            se.test151 = 5;
            se.test152 = 5;
            se.test153 = 5;
            se.test154 = 5;
            se.test155 = 5;
            se.test156 = 5;
            se.test157 = 5;
            se.test158 = 5;
            se.test159 = 5;
            se.test160 = 5;
            se.test161 = 5;
            se.test162 = 5;
            se.test163 = 5;
            se.test164 = 5;
            se.test165 = 5;
            se.test166 = 5;
            se.test167 = 5;
            se.test168 = 5;
            se.test169 = 5;
            outputtime("Time to Run SuperExpando, set 50 test key/value pairs -- (not even setting values, just returning true from TrySetMember!)");

            dynamic eo = new ExpandoObject();
            outputtime("Declared ExpandoObject");
            eo.test120 = 5;
            eo.test121 = 5;
            eo.test122 = 5;
            eo.test123 = 5;
            eo.test124 = 5;
            eo.test125 = 5;
            eo.test126 = 5;
            eo.test127 = 5;
            eo.test128 = 5;
            eo.test129 = 5;
            eo.test130 = 5;
            eo.test131 = 5;
            eo.test132 = 5;
            eo.test133 = 5;
            eo.test134 = 5;
            eo.test135 = 5;
            eo.test136 = 5;
            eo.test137 = 5;
            eo.test138 = 5;
            eo.test139 = 5;
            eo.test140 = 5;
            eo.test141 = 5;
            eo.test142 = 5;
            eo.test143 = 5;
            eo.test144 = 5;
            eo.test145 = 5;
            eo.test146 = 5;
            eo.test147 = 5;
            eo.test148 = 5;
            eo.test149 = 5;
            eo.test150 = 5;
            eo.test151 = 5;
            eo.test152 = 5;
            eo.test153 = 5;
            eo.test154 = 5;
            eo.test155 = 5;
            eo.test156 = 5;
            eo.test157 = 5;
            eo.test158 = 5;
            eo.test159 = 5;
            eo.test160 = 5;
            eo.test161 = 5;
            eo.test162 = 5;
            eo.test163 = 5;
            eo.test164 = 5;
            eo.test165 = 5;
            eo.test166 = 5;
            eo.test167 = 5;
            eo.test168 = 5;
            eo.test169 = 5;
            outputtime("Time to Run ExpandoObject, set 50 test key/value pairs");
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
运用系统动力学;
名称空间测试
{
公共部分类ExpandoTest:表单
{
公共扩展测试()
{
初始化组件();
}
公共类SuperExpando:DynamicObject
{
公共字典=新字典();
public override bool TrySetMember(SetMemberBinder绑定器,对象值)
{
//字典[binder.Name]=值;
返回true;
}
}
DateTime lasttime=DateTime.Now;
公共无效输出时间(字符串标签=“”)
{
TimeSpan elapsedtime=DateTime.Now-lasttime;
Double elapsedms=elapsedtime.Total毫秒;
Console.WriteLine(标签+”:“+elapsedms.ToString());
lasttime=DateTime.Now;
}
私有void go\u单击(对象发送者,事件参数e)
{
输出时间(“等待用户的时间”);
动态se=新的SuperExpando();
输出时间(“声明的超级扩展”);
se.test120=5;
se.test121=5;
se.test122=5;
se.test123=5;
se.test124=5;
se.test125=5;
se.test126=5;
se.test127=5;
se.test128=5;
se.test129=5;
se.test130=5;
se.test131=5;
se.test132=5;
se.test133=5;
se.test134=5;
se.test135=5;
se.test136=5;
se.test137=5;
se.test138=5;
se.test139=5;
se.test140=5;
se.test141=5;
se.test142=5;
se.test143=5;
se.test144=5;
se.test145=5;
se.test146=5;
se.test147=5;
se.test148=5;
se.test149=5;
se.test150=5;
se.test151=5;
se.test152=5;
se.test153=5;
se.test154=5;
se.test155=5;
se.test156=5;
se.test157=5;
se.test158=5;
se.test159=5;
se.test160=5;
se.test161=5;
se.test162=5;
se.test163=5;
se.test164=5;
se.test165=5;
se.test166=5;
se.test167=5;
se.test168=5;
se.test169=5;
outputtime(“运行SuperExpando的时间到了,设置50个测试键/值对——(甚至没有设置值,只是从TrySetMember返回true!);
动态eo=新的ExpandooObject();
输出时间(“声明的扩展对象”);
eo.test120=5;
eo.test121=5;
eo.test122=5;
eo.test123=5;
eo.test124=5;
eo.test125=5;
eo.test126=5;
eo.test127=5;
eo.test128=5;
eo.test129=5;
eo.test130=5;
eo.test131=5;
eo.test132=5;
eo.test133=5;
eo.test134=5;
eo.test135=5;
eo.test136=5;
eo.test137=5;
eo.test138=5;
eo.test139=5;
eo.test140=5;
eo.test141=5;
eo.test142=5;
eo.test143=5;
eo.test144=5;
eo.test145=5;
eo.test146=5;
eo.test147=5;
eo.test148=5;
eo.test149=5;
eo.test150=5;
eo.test151=5;
eo.test152=5;
eo.test153=5;
eo.test154=5;
eo.test155=5;
eo.test156=5;
eo.test157=5;
eo.test158=5;
eo.test159=5;
eo.test160=5;
eo.test161=5;
eo.test162=5;
eo.test163=5;
eo.test164=5;
eo.test165=5;
eo.test166=5;
eo.test167=5;
eo.test168=5;
eo.test169=5;
outputtime(“运行ExpandooObject的时间,设置50个测试键/值对”);
}
}
}

首先,你不应该这样测量时间<代码>日期时间。现在不精确到毫秒。您应该使用秒表进行此操作

第二,在.Net中,尤其是在处理
动态
时,顺序很重要。
dictionary[binder.Name] = value;
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    if (dictionary.ContainsKey(binder.Name))
    {
        result = dictionary[binder.Name];
        return true;
    }
    return false; 
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Dynamic;

namespace test
{
    public partial class ExpandoTest : Form
    {
        public ExpandoTest()
        {
            InitializeComponent();
        }

        public class SuperExpando : DynamicObject
        {
            public Dictionary<string, object> dictionary = new Dictionary<string, object>();

            public override bool TrySetMember(SetMemberBinder binder, object value)
            {
                //dictionary[binder.Name] = value;
                return true;
            }
        }

        DateTime lasttime = DateTime.Now;

        public void outputtime(string label = "")
        {
            TimeSpan elapsedtime = DateTime.Now - lasttime;
            Double elapsedms = elapsedtime.TotalMilliseconds;
            Console.WriteLine(label + " : " + elapsedms.ToString());
            lasttime = DateTime.Now;
        }

        private void go_Click(object sender, EventArgs e)
        {
            outputtime("Time spent waiting on user");
            dynamic se = new SuperExpando();
            outputtime("Declared SuperExpando");
            se.test120 = 5;
            se.test121 = 5;
            se.test122 = 5;
            se.test123 = 5;
            se.test124 = 5;
            se.test125 = 5;
            se.test126 = 5;
            se.test127 = 5;
            se.test128 = 5;
            se.test129 = 5;
            se.test130 = 5;
            se.test131 = 5;
            se.test132 = 5;
            se.test133 = 5;
            se.test134 = 5;
            se.test135 = 5;
            se.test136 = 5;
            se.test137 = 5;
            se.test138 = 5;
            se.test139 = 5;
            se.test140 = 5;
            se.test141 = 5;
            se.test142 = 5;
            se.test143 = 5;
            se.test144 = 5;
            se.test145 = 5;
            se.test146 = 5;
            se.test147 = 5;
            se.test148 = 5;
            se.test149 = 5;
            se.test150 = 5;
            se.test151 = 5;
            se.test152 = 5;
            se.test153 = 5;
            se.test154 = 5;
            se.test155 = 5;
            se.test156 = 5;
            se.test157 = 5;
            se.test158 = 5;
            se.test159 = 5;
            se.test160 = 5;
            se.test161 = 5;
            se.test162 = 5;
            se.test163 = 5;
            se.test164 = 5;
            se.test165 = 5;
            se.test166 = 5;
            se.test167 = 5;
            se.test168 = 5;
            se.test169 = 5;
            outputtime("Time to Run SuperExpando, set 50 test key/value pairs -- (not even setting values, just returning true from TrySetMember!)");

            dynamic eo = new ExpandoObject();
            outputtime("Declared ExpandoObject");
            eo.test120 = 5;
            eo.test121 = 5;
            eo.test122 = 5;
            eo.test123 = 5;
            eo.test124 = 5;
            eo.test125 = 5;
            eo.test126 = 5;
            eo.test127 = 5;
            eo.test128 = 5;
            eo.test129 = 5;
            eo.test130 = 5;
            eo.test131 = 5;
            eo.test132 = 5;
            eo.test133 = 5;
            eo.test134 = 5;
            eo.test135 = 5;
            eo.test136 = 5;
            eo.test137 = 5;
            eo.test138 = 5;
            eo.test139 = 5;
            eo.test140 = 5;
            eo.test141 = 5;
            eo.test142 = 5;
            eo.test143 = 5;
            eo.test144 = 5;
            eo.test145 = 5;
            eo.test146 = 5;
            eo.test147 = 5;
            eo.test148 = 5;
            eo.test149 = 5;
            eo.test150 = 5;
            eo.test151 = 5;
            eo.test152 = 5;
            eo.test153 = 5;
            eo.test154 = 5;
            eo.test155 = 5;
            eo.test156 = 5;
            eo.test157 = 5;
            eo.test158 = 5;
            eo.test159 = 5;
            eo.test160 = 5;
            eo.test161 = 5;
            eo.test162 = 5;
            eo.test163 = 5;
            eo.test164 = 5;
            eo.test165 = 5;
            eo.test166 = 5;
            eo.test167 = 5;
            eo.test168 = 5;
            eo.test169 = 5;
            outputtime("Time to Run ExpandoObject, set 50 test key/value pairs");
        }
    }
}
SuperExpando: 50,7736 ms
EpandoObject: 27,786 ms
SuperExpando: 0,0285 ms
EpandoObject: 0,0373 ms
EpandoObject: 33,3107 ms
SuperExpando: 43,7383 ms
EpandoObject: 0,0348 ms
SuperExpando: 0,0186 ms