【问题标题】:Good or Bad Practice for Return Members返回会员的好坏习惯
【发布时间】:2012-12-28 19:38:37
【问题描述】:

我不确定这是否是无效的做法;或良好的做法。我不知所措的原因是我应该使用属性而不是局部变量吗?

我的推理和目标;是对本地磁盘驱动器的非常基本的检测。

我想指出一些事情:

  • 我没有选择boolean value,因为我希望能够调用这个类来返回驱动器路径。因此从方法中检索到的名称;在某些派生类中可以是Path Combined

我的例子:

    public class Drive
    {
        // Variable:
        public string nameOfDrive;

        public Drive()
        {
            // Call Method.
            DriveName();
        }

        public string DriveName()
        {
            DriveInfo [] drives = DriveInfo.GetDrives();
            foreach (DriveInfo d in drives)
            {
                // Verify Valid 'C:' is Present.
                if (d.Name == @"C:")
                {
                    // Set Name:
                    nameOfDrive = d.Name;
                    // Return Result.
                    return d.Name;
                }
            }
            // Exception:
            throw new Exception("Unable to locate the C: Drive... Please map the correct drive.");
        }

    }
    /*
     * The above method and class contains a verification
     * for the 'C:' Drive.  Once the items are validated;
     * it will create a return variable for the 'C:'.  
     * Otherwise it will throw an Exception.
    */

现在我不确定什么是更好的做法。我应该使用属性而不是public string nameOfDrive。还是我真的很遥远-这不是返回可在其他类中使用的值的最佳方法吗?还是直接引用成员变量是不好的做法?

第二个例子:

    public class Drive
    {
        private string nameOfDrive;
        public string NameOfDrive
        {
            get { return nameOfDrive; }
        }
        public Drive()
        {
            // Call Method.
            DriveName();
        }
        public string DriveName()
        {
            // Obtain Drive Information:
            DriveInfo [] drives = DriveInfo.GetDrives();
            foreach (DriveInfo d in drives)
            {
                // Verify Valid 'C:' is Present.
                if (d.Name == @"C:")
                {
                    // Set Name:
                    nameOfDrive = d.Name;
                    // Return Result.
                    return d.Name;
                }
            }
            // Exception:
            throw new Exception("Unable to locate the C: Drive... Please map the correct drive.");
        }
    }
    /*
     * The above method and class contains a verification
     * for the 'C:' Drive.  Once the items are validated;
     * it will create a return variable for the 'C:'.  
     * Otherwise it will throw an Exception.
    */

这样它就被标记为只读并确保它从方法中读取正确的值?


更新:

感谢您的回答;但是为什么这是更好的做法?

  • 对安全有好处吗?
  • 更整洁?
  • 更灵活

是什么使它成为更好的解决方案;这就是我试图理解的。

【问题讨论】:

  • 您确实需要从这些示例中减少代码膨胀。我们不需要看到你的使用、命名空间,我们不需要所有的空格、区域和冗余的 cmets 等。特别是在比较两个代码 sn-ps 时,当所有这些不相关时,更难看出差异杂乱无章的排序虽然。即使您将所有这些都保留在实际代码中,也要在将其发布到此处之前对其进行过滤。
  • @Servy 我修好了。此外,无论是否有示例代码,您的代码中都不需要 20 个空行,也不需要随机无意义的区域和“自定义”注释文档约定。您可能想将您的一些代码带到codereview.stackexchange.com,以了解有关您的编码风格有什么问题的更多信息

标签: c# variables methods


【解决方案1】:

您可以使用Lazy 类来执行此操作。它专门用于解决延迟初始化可能需要一些时间来计算的值的确切问题。您可以为Lazy 对象提供一个用于计算值的方法,第一次请求该值时,它使用该函数生成该值,并且所有后续调用仅返回该第一个值。它还具有线程安全的优点(该函数只会被调用一次,无论有多少人在生成该值之前请求该值,并且他们都等到它被计算返回)。

public class Drive
{
    private Lazy<string> nameOfDrive = new Lazy<string>(DriveName);

    public string NameOfDrive
    {
        get { return nameOfDrive.Value; }
    }

    private static string DriveName()
    {
        DriveInfo[] drives = DriveInfo.GetDrives();

        foreach (DriveInfo d in drives)
        {
            if (d.Name == @"C:")
                return d.Name;
        }

        throw new Exception("Unable to locate the C: Drive... Please map the correct drive.");
    }
}

【讨论】:

  • 谢谢你的解释;这更好地解释了我为什么要使用上述方法。
【解决方案2】:

我会使用带有私有成员变量的只读属性。这样,如果您在不破坏调用代码的情况下更改了查找驱动器号的方式,就可以更轻松地更新类。

为什么您的DriveName 方法会返回任何内容?它是公开使用还是仅用于填充您的 NameOfDrive 属性?如果仅在课堂内使用,我会将其设为私有且无效。

编辑:考虑一下,这似乎也是一种奇怪的方式,不仅可以检查驱动器是否存在,还可以检查开头的字母。为什么要求用户的盘符是C:?用户设置机器的方式无关紧要。如果他们愿意,他们应该能够将他们的操作系统驱动器设置为 Q:,并且它不应该破坏您的代码。

【讨论】:

  • 嗯,Crystal Reports 会在本地C: 上生成一个临时目录。如果它不存在,则会引发异常。所以作为一个练习,我想我会构建一个小检查器。
  • 只用于生成NameOfDrive属性。
【解决方案3】:

虽然,这不一定是坏习惯,但也不好。

在大多数情况下,当你有一个简单的数据类时应该使用字段(通常不涉及真正的代码,只是一种存储一些值的方法)。如果您超出了该级别的复杂性,您通常应该让您的类使用属性。几个原因:

  1. 稍后从字段转换为属性将破坏依赖关系并要求重新编译使用您的类的所有代码
  2. 属性具有更细粒度的控制。快速浏览一下您的用例,您似乎应该有一个 getter,它会自动填充和缓存驱动器号,并将默认的 setter 设为私有,因此它是只读的
  3. 属性可以是虚拟的。这意味着人们可以更容易地将您的课程扩展到您最初想象的之外。

【讨论】:

  • 谢谢,这是一个很好的解释!
  • 我不同意你的说法“在大多数情况下,当你有一个简单的数据类时应该使用字段”。 Microsoft 和 .Net 尽可能地推动属性,几乎完全不鼓励公共领域。看看自动属性(3.0 中的新功能)、实体框架模板等。由于您列出的所有原因以及数据绑定和反射之类的东西,这都是正确的。 .Net 中(几乎)没有理由再使用公共字段了
  • @EkoostikMartin 是的,我使用自动属性等。在某些情况下,我知道我永远不需要属性的功能,通常在仅用于存储一些数据的私有嵌套类中。但是,即使在那里,您是对的,字段几乎毫无意义。大多数处理反射(序列化等)的东西在使用属性而不是字段时可以完全或更好地工作
【解决方案4】:

我会创建一个类(甚至是扩展)来提取 cdrive。让消费者根据他们的需要抛出错误。

通过创建通用方法,允许根据情况重用流程,并坚持使用面向对象的原则,将概念隔离为唯一的对象。

void Main()
{

  if (Drive.AcquireCDrive() == null)
      throw new Exception("Unable to locate the C: Drive... Please map the correct drive.");

}

public class Drive
{
    public static DriveInfo AcquireCDrive()
    {
       return DriveInfo.GetDrives()
                       .OfType<DriveInfo>()
                       .Where (drive => drive.IsReady)
                       .FirstOrDefault( drive => drive.Name.Contains(@"C:"));
    }
} 

【讨论】:

  • 这实际上是一种非常巧妙的方法;我喜欢这样。
  • 既然他想要在没有选项存在的情况下出现异常,我会选择First而不是FirstOrDefault
【解决方案5】:

可能更好的做法是使用只读属性,但延迟加载它。

注意下面,我将DriveName()方法设为私有,并没有在构造函数中调用DriveName()方法。

public class Drive
{
    private string nameOfDrive = null;

    public string NameOfDrive
    {
        get 
        {
            if (nameOfDrive == null)
                nameOfDrive = DriveName();
            return nameOfDrive; 
        }
    }

    public Drive()
    {    }

    private string DriveName()
    {
        DriveInfo[] drives = DriveInfo.GetDrives();

        foreach (DriveInfo d in drives)
        {
            if (d.Name == @"C:")            
                return d.Name;
        }

        throw new Exception("Unable to locate the C: Drive... Please map the correct drive.");
    }
}

【讨论】:

  • 您可以专门使用Lazy&lt;T&gt; 类来执行此操作。您不仅可以稍微简化代码,而且它会变得线程安全(您的代码目前不是)。
  • @Servy 我不认为Lazy&lt;T&gt; 使代码更简单,考虑到目标受众(原始海报)。也不要认为在这种情况下线程安全是一个问题。
  • @Greg 好吧,我说的是这个答案,但既然他建议你使用它,它显然适用于两者。
  • @EkoostikMartin 好吧,我添加了一个答案只是为了展示它的外观。对我来说似乎更简单。这当然是更少的代码。无论它是否真的 需要 是线程安全的,在做 less 工作的同时免费获得它似乎是合适的,因为我不知道该方法的当前或未来上下文。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
  • 2013-07-17
  • 2015-08-10
  • 1970-01-01
  • 2017-12-09
相关资源
最近更新 更多