使用匿名方法以避免创建一次性对象

本文关键字:创建 一次性 对象 方法 | 更新日期: 2023-09-27 18:21:55

我正在尝试重构一个解析文件的方法。为了支持任意大小的文件,该方法使用具有固定缓冲区的分块方法。

public int Parse()
{
    // Get the initial chunk of data
    ReadNextChunk();
    while (lengthOfDataInBuffer > 0)
    {
       [parse through contents of buffer]
       if (buffer_is_about_to_underflow)
          ReadNextChunk();
    }
    return result;
}

上面的伪代码是类中唯一的公共非静态方法(构造函数除外)的一部分。类的存在只是为了封装在解析文件时必须跟踪的状态。此外,一旦在类上调用了此方法,就不能/不应该再次调用它。因此使用模式如下:

var obj = new MyClass(filenameToParse);
var result = obj.Parse();
// Never use 'obj' instance again after this.

出于某种原因,这让我很恼火。我可以将MyClass构造函数设置为私有的,将Parse更改为静态方法,并使Parse方法在该方法的范围内新建一个Parse实例。这将产生如下的使用模式:

var result = MyClass.Parse(filenameToParse);

MyClass不是一个静态类;我仍然需要在Parse方法中创建一个本地实例。

由于这个类只有两个方法;Parse和(私有)ReadNextChunk,我想知道通过将ReadNextCchunk逻辑作为匿名方法嵌入Parse中,将Parse作为一个单一的静态方法编写是否更干净。状态的其余部分可以作为局部变量而不是成员变量进行跟踪。

当然,我可以通过将ReadNextChunk作为一个静态方法,然后传入所有上下文来完成类似的事情,但我记得anon方法可以访问外部范围。

这是一种怪异和丑陋的做法,还是一种合理的做法?

使用匿名方法以避免创建一次性对象

这可能更适合代码审查。

然而,以下是我对你的设计的评论:

  1. 我认为obj实例只使用一次并不重要。如果你遇到了麻烦,有两种方法可以欺骗它:

    • 使用其他方法,例如:

      public int Parse()
      {
          var obj = new MyClass(filenameToParse);
          return obj.Parse();
      }
      
    • 使MyClass实现IDisposable,并将其封装在using语句中。我不建议这样做,因为通常IDisposable在他们的Dispose()方法中有逻辑

  2. 我认为最好让你的MyClass接受ParseParse(string fileNameToParse)中的参数。它将使MyClass成为一个服务类,使其成为无状态的、可重用的和可注入的。

  3. 关于对静态类的影响。首先,它添加了消费者和MyClass之间的耦合。有时,如果你想在不使用MyClass解析器的情况下测试/单元测试consumer,那么很难/不可能将MyClass模拟成你想要的东西。

您所需要的只是一个创建实例的静态解析方法,就像您在问题中建议的那样

public class MyClass
{
     // your existing code.... but make the members and constructor private.

     public static int Parse(string filenameToParse)
     {
         return new MyClass(filenameToParse).Parse();
     }
}

然后

按照你的建议使用它。。。

var result = MyClass.Parse(filenameToParse);

MyClass不是一个静态类;我仍然需要创建一个本地Parse方法中的实例。

您不需要一个静态类就可以利用静态方法。例如,这很好:

public class MyClass
{
    public static string DoStuff(string input)
    {
        Console.WriteLine("Did stuff: " + input);
        return "Did stuff";
    }
}
public class Host
{
    public void Main()
    {
        MyClass.DoStuff("something");
    }
}