c# - 如何在 C# 中强制使用方法的返回值?

标签 c# compiler-construction attributes lazy-loading return-value

我有一个用流利语法编写的软件。方法链有一个明确的“结尾”,在此之前代码中实际上没有做任何有用的事情(想想 NBuilder,或者 Linq-to-SQL 的查询生成实际上并没有访问数据库,直到我们使用 ToList() 遍历我们的对象).

我遇到的问题是其他开发人员对代码的正确使用感到困惑。他们忽略了调用“结束”方法(因此从未真正“做任何事”)!

我对强制使用我的一些方法的返回值感兴趣,这样我们就永远不会在不调用“Finalize()”或“Save()”的情况下“结束链”实际完成工作的方法。

考虑以下代码:

//The "factory" class the user will be dealing with
public class FluentClass
{
    //The entry point for this software
    public IntermediateClass<T> Init<T>()
    {
        return new IntermediateClass<T>();
    }
}

//The class that actually does the work
public class IntermediateClass<T>
{
    private List<T> _values;

    //The user cannot call this constructor
    internal IntermediateClass<T>()
    {
        _values = new List<T>();
    }

    //Once generated, they can call "setup" methods such as this
    public IntermediateClass<T> With(T value)
    {
        var instance = new IntermediateClass<T>() { _values = _values };
        instance._values.Add(value);
        return instance;
    }

    //Picture "lazy loading" - you have to call this method to
    //actually do anything worthwhile
    public void Save()
    {
        var itemCount = _values.Count();
        . . . //save to database, write a log, do some real work
    }
}

如您所见,正确使用这段代码应该是这样的:

new FluentClass().Init<int>().With(-1).With(300).With(42).Save();

问题是人们正在这样使用它(认为它实现了与上面相同的效果):

new FluentClass().Init<int>().With(-1).With(300).With(42);

这个问题非常普遍,以至于另一位开发人员曾经出于好意实际上更改了“Init”方法的名称,以表明该方法正在执行软件的“实际工作”。

像这样的逻辑错误很难发现,当然,它可以编译,因为调用一个有返回值的方法并“假装”它返回 void 是完全可以接受的。 Visual Studio 不关心你是否这样做;您的软件仍将编译并运行(尽管在某些情况下我相信它会发出警告)。当然,这是一个很棒的功能。想象一个简单的“InsertToDatabase”方法,它以整数形式返回新行的 ID - 很容易看出,在某些情况下我们需要该 ID,而在某些情况下我们可以不需要它。

对于这款软件,绝对没有任何理由在方法链末尾避开“保存”功能。这是一个非常专业的实用程序,唯一的收获来自最后一步。

如果某人的软件调用“With()”而不是“Save()”,我希望他们的软件在编译器级别失败

这似乎是传统方法不可能完成的任务 - 但这就是我来找你们的原因。有没有我可以用来防止方法被“强制转换为无效”或类似方法的属性?

注意: 已向我建议实现此目标的替代方法是编写一套单元测试来执行此规则,并使用类似 http://www.testdriven.net 的方法。将它们绑定(bind)到编译器。这是一个可以接受的解决方案,但我希望有更优雅的解决方案。

最佳答案

我不知道有什么方法可以在编译器级别强制执行此操作。它也经常被要求用于实现 IDisposable 的对象,但并不是真正可执行的。

然而,一个可能有用的选项是设置您的类,仅在 DEBUG 中,以具有记录/抛出/等的终结器。如果从未调用过 Save()。这可以帮助您在调试时发现这些运行时问题,而不是依赖于搜索代码等。

但是,请确保在 Release模式下不使用它,因为它会产生性能开销,因为添加不必要的终结器对 GC 性能非常不利。

关于c# - 如何在 C# 中强制使用方法的返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5410978/

相关文章:

r - 什么是对象?

c# - Pkcs11Interop CKR_ENCRYPTED_DATA_INVALID 异常导致 CPU 使用率高

c# - 在 UWP 中更新绑定(bind)的项目源后如何更新 GridView?

c++ - C++ 中的常量和编译器优化

c - 为什么不同的 C 编译器可以为 C 程序提供不同的输出?

ruby - 在 ruby​​ 中获取 attr_accessor/实例变量

c# - Attribute.GetCustomAttributes 和 MemberInfo.GetCustomAttributes 可以互换吗?

c# - 使用 winforms 在 c# 中处理跨方法列表

c# - 在 System.Windows.Forms.DataGrid 中设置 double/float/decimal 的精度

c# - IL 知道什么是接口(interface)吗?