CRM 2011插件 - 使用早期绑定实体的属性名称会导致内存问题吗?

时间:2013-04-29 21:41:01

标签: c#-4.0 memory-management dynamics-crm-2011

在我的插件代码中,我使用早期绑定实体(通过crmsvcutil生成)。在我的代码中,我使用MemberExpression来检索属性的名称。例如,如果我想要启动插件的用户的全名,请执行以下操作

SystemUser pluginExecutedBy = new SystemUser();
pluginExecutedBy = Common.RetrieveEntity(service
                                        , SystemUser.EntityLogicalName
                                        , new ColumnSet(new string[] {Common.GetPropertyName(() => pluginExecutedBy.FullName)})
                                        , localContext.PluginExecutionContext.InitiatingUserId).ToEntity<SystemUser>();

GetPropertyName的代码如下

    public static string GetPropertyName<T>(Expression<Func<T>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        return body.Member.Name.ToLower();
    }

RetrieveEntity的代码如下

public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
        {
            return (Entity)xrmService.Retrieve(entityName, entityId, columns);
        }

我的解决方案架构师的评论:

不是像上面那样编写代码,为什么不这样编写它(硬编码字段的名称 - 或使用结构)。

SystemUser pluginExecutedBy = null;
pluginExecutedBy = Common.RetrieveEntity(service
                                        , SystemUser.EntityLogicalName
                                        , new ColumnSet(new string[] {"fullname"})
                                        , localContext.PluginExecutionContext.InitiatingUserId).ToEntity<SystemUser>();

原因

  1. 您的代码在需要它之前不必要地创建一个对象(当您在RetrieveEntity之前使用new关键字实例化对象以便将其与我的GetProperty方法一起使用时)这是一种糟糕的编程习惯。在我的代码中,我从未使用new关键字,但只是强制转换它并且转换不会创建新对象。 现在,我不是C#或.NET的专家,但我喜欢阅读并尝试不同的东西。所以,我查找了Microsoft.Xrm.Sdk.dll并发现Sdk中的ToEntity实际上确实使用关键字new创建了一个新的实体。
  2. 如果Common.Retrieve返回null,那么您的代码会不必要地分配内存,这会导致性能问题,而我的代码不会? 像C#这样的托管语言管理内存&#34;对我来说,不是吗?
  3. 问题

    1. 我的代码写得不好吗?如果是这样,为什么?如果它更好 - 为什么? (我相信它更清洁,即使字段名称发生变化,只要重新生成早期绑定类文件,我就不必重新编写任何代码)

    2. 我同意强制转换不会创建新对象,但我的代码是否会不必要地创建对象?

    3. 编写代码有更好的方法(完全不同的第三种方式)吗?

    4. 注意:我建议使用GetPropertyName,因为他在整个代码中都是硬编码属性名称,所以在一个不使用早期绑定实体的不同项目中,我使用了属性名称的结构 - 如下所示。我在CRM 2011的新工作中做了3周,但后来发现了MemberExpression的神奇之处。他正在为他在插件中使用的每个实体编写一个大量的cs文件,我告诉他他不必做任何这些,因为他可以在他的插件中使用我的GetPropertyName方法并获得所需的所有字段这促使此代码审查评论。通常他不会进行代码审查。

      public class ClientName
      {
          public struct EntityNameA
          {
              public const string LogicalName = "new_EntityNameA";
              public struct Attributes
              {
                  public const string Name = "new_name";
                  public const string Status = "new_status";
              }
          }
      }
      

      PS:或者分析不值得的问题/时间是什么?

2 个答案:

答案 0 :(得分:3)

Early Bound,Late Bound,MemberExpression,bla bla bla :))

我可以理解“哲学”,但是在我的脑海中看着你的代码是一个巨大的警报:

public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
        {
            return (Entity)xrmService.Retrieve(entityName, entityId, columns);
        }

Retrieve如果找不到记录则会引发异常

关于其他事情,GetPropertyName是好的,但总是选择,例如我尝试使用总是在插件中的后期绑定,也许在项目中我更喜欢使用早期绑定,通常有更多解决问题的一种方法。

快乐的crm编码!

答案 1 :(得分:2)

尽管GetPropertyName是一个非常聪明的解决方案,我不喜欢它,这完全与可读性有关。对我来说,更容易理解发生了什么:new ColumnSet(new string[] {"fullname"})

但这几乎是个人偏好,但重要的是要记住,不仅为自己编写代码,而是为团队编写代码,他们应该能够轻松理解您所做的工作。

作为一方,硬编码字符串可能在运行时表现更好。我通常硬编码我的所有值,如果CRM中的实体模型发生变化,我将不得不重新考虑在任何情况下进行更改。在那种情况下,早期和晚期之间没有区别。

我不明白这个功能的意义,

public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
{
    return (Entity)xrmService.Retrieve(entityName, entityId, columns);
}

它没有做任何事情(除了演员已经属于那种类型)。

  

1.您的代码在需要它之前不必要地创建一个对象(当您使用new关键字实例化对象之前   RetrieveEntity以便与我的GetProperty方法一起使用)   糟糕的编程习惯。在我的代码中,我从未使用过新的代码   关键字,但只是铸造它和铸造不会创建一个新的   对象

我相信这是指; SystemUser pluginExecutedBy = new SystemUser();我可以在这里看到他/她的观点,在这种情况下new SystemUser()没有做太多,但如果你实例化的对象做了一些资源密集(加载文件,打开数据库连接),你可能会做一些“浪费”的事情。在这种情况下,如果改变SystemUser pluginExecutedBy = null;实际上会产生任何显着的性能提升,我会感到惊讶。

  

2.如果Common.Retrieve返回null,则代码会不必要地分配内存,从而导致性能问题

如果引起性能问题,我会感到惊讶,无论如何,Guido指出函数在任何情况下都不会返回null。

总的来说,这个代码很少,我强烈感觉需要改变 - 但事情可能总是更好,值得讨论(例如代码审查的重点),尽管你可能很难不对你的代码。

我个人会使用硬编码的属性名称并转储Common.RetrieveEntity函数,因为它没有做任何事情。

pluginExecutedBy = service.Retrieve(SystemUser.EntityLogicalName, localContext.PluginExecutionContext.InitiatingUserId, new ColumnSet(new String[] {"fullname"} ));