【问题标题】:Is it a good practice to perform initialization within a Property?在属性中执行初始化是一个好习惯吗?
【发布时间】:2014-08-11 05:21:09
【问题描述】:

我有一个类 PluginProvider,它使用 PluginLoader 组件从文件系统加载插件(托管/本机)。在 PluginProvider 类中,当前定义了一个名为“PluginTypes”的属性,该属性调用 get() 上的“InitializePlugins”实例方法。

class PluginProvider
 {
   IEnumerable<IPluginType> PluginTypes
   {
     get
     {
        //isInitialized is set inside InitializePlugins method
        if(!isInitialized)
        {
           InitializePlugins(); //contains thread safe code
        }
        //_pluginTypes is set within InitializePlugins method
        return _pluginTypes;
     }
   }
 }

我正在考虑重构这段代码。我想知道这种初始化是否可以在属性中进行。我知道不能在财产中进行繁重的操作。但是当我检查这个链接时:http://msdn.microsoft.com/en-us/library/vstudio/ms229054.aspx,发现这个“特别是,访问网络或文件系统的操作(除了一次初始化)应该很可能是方法,而不是属性。” .现在我有点困惑。请帮忙。

【问题讨论】:

    标签: c# methods properties design-guidelines


    【解决方案1】:
    • 如果您想尽可能延迟初始化并且您不知道何时您的属性(或多个属性)将被调用,那么您正在做的事情很好。
    • 如果您想延迟并且可以控制何时首次调用您的属性,那么您可能希望将您的方法InitializePlugins() 公开并在访问该属性之前显式调用它。此选项还开启了异步初始化的可能性。例如,您可以有一个InitializePluginsAsync(),它返回一个Task
    • 如果延迟初始化不是一个大问题,那么只需在构造函数中执行初始化即可。

    【讨论】:

    • 感谢您的回复。对我来说,延迟初始化不是问题。同时,我不想用昂贵的操作“超载”构造函数。这是在应用程序启动时发生的事情,在访问属性之前。因此,我觉得我可以选择第二个选项。
    • @Naveen 我可能也会选择第二个选项,并实现异步模式(因为您提到该操作非常昂贵)。否则,我不会太在意使用构造函数或从构造函数中抛出异常。这些都很好,.Net Framework 中有示例(例如,参见 FileStream 类)。
    【解决方案2】:

    这当然是一个品味问题。但我会做什么取决于您尝试执行的操作的长度。如果加载插件需要时间,我将创建一个公共方法,任何用户在使用该类之前都需要调用该方法。另一种方法是将方法放在构造函数中,但 IMO 构造函数应尽快返回,并应包含字段/属性初始化。

    class PluginProvider
    {
        private bool _isInitialized;
        IEnumerable<IPluginType> PluginTypes { get; set;}
    
        public void Initialize()
        {
            if (_isInitialized)
            {
                 return;
            }      
    
            InitializePlugins();
            _isInitialized = true;  
        }
    }
    

    请注意,这样做的缺点是您必须确保在执行任何操作之前调用了 Initialize 方法。

    刚想到支持这种方法的另一件事是异常处理。我确定你不希望你的构造函数抛出任何类型的IOException,以防它无法从文件系统加载类型。

    【讨论】:

    • 是的,我有同样的担忧:1)插件加载是一项昂贵的操作,可能有数百个插件,2)构造函数抛出异常的风险。由于插件加载发生在应用程序启动时,我可以将 InitializePlugins() 设为公共并在访问该类的任何属性之前调用它。
    【解决方案3】:

    任何初始化类型的代码都应该在构造函数中完成,这样你就知道它只会被调用一次。

    public class PluginProvider
    {
       IEnumerable<IPluginType> PluginTypes
       {
          get
          {
            return _pluginTypes;
          }
       }
    
       public PluginProvider()
       {
          InitializePlugins();
       }
    }
    

    【讨论】:

    • 感谢您的回复。这有两个问题: 1. 加载插件是一项昂贵的操作,我希望构造函数快速返回。 2. 异常处理,正如@Yuval Itzchakov 在其中一个答案中提到的那样。
    【解决方案4】:

    您在那里所做的事情称为延迟初始化。您将执行一项可能成本高昂的操作推迟到需要其输出的那一刻。

    现在,这不是一个绝对的规则。如果您的 InitializePlugins 方法需要很长时间才能完成并且可能会影响用户体验,那么您可以考虑将其移至公共方法中,甚至使其异步并在属性之外调用它:在应用启动时或每当您发现进行长期手术的好时机。

    否则,如果它是短暂的一次性事物,它可以留在那里。正如我所说,不是绝对规则。一般来说,这些是适用于特定案例的一些指导方针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-31
      • 2018-10-15
      • 2012-03-10
      • 2016-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-21
      相关资源
      最近更新 更多