检测未分配的局部变量的错误(当动态变量影响代码流预测时)

2023-12-11

文档意味着 out 参数在发送到函数之前不需要初始化(只需声明)。然而,这段代码:

class Program
{
    static void Main()
    {
        dynamic p = "";
        string s;
        if (p != null && T(out s))
            System.Console.WriteLine(s);
    }

    static bool T(out string s)
    {
        s = "";
        return true;
    }
}

给出了build error:

使用未分配的局部变量“s”

只有当p is dynamic. If p键入为string or object,不会产生错误。

方法T是required在返回之前设置变量,所以这个错误对我来说似乎是废话(请注意,即使使用短路 &&,第二条语句也必须执行才能执行“then”块)。

注:您也可以下载这个回购协议重现。

那么,这是一个合法的错误吗(我使用的是 C# 7.0)?我应该如何处理这个问题?


更新:这个问题是我2018年11月博客的主题。感谢您提出有趣的问题!

该文档暗示out参数在发送到方法之前不需要初始化(只需声明)。

这是正确的。此外,一个变量传递给out当调用返回时,参数肯定被分配,因为正如您所注意到的:

方法 T 需要在返回之前设置变量,所以这个错误对我来说似乎是废话

看起来是这样,不是吗?外表会骗人!

请注意,即使短路&&,第二个表达式必须执行才能执行“结果”块if执行。

令人惊讶的是,这是错误的。即使调用了,也有一种方法可以执行结果T不执行。这样做需要我们严重滥用 C# 的规则,但是我们can,所以让我们开始吧!

代替

    dynamic p = "";
    string s;
    if (p != null && T(out s))
        System.Console.WriteLine(s);

干的好

    P p = new P();
    if (p != null && T())
        System.Console.WriteLine("in the consequence");

并给出定义class P这会导致该程序运行结果但是not运行调用T.

我们要做的第一件事就是转p != null进入方法调用而不是空检查,并且该方法不得返回bool:

class P
{
    public static C operator ==(P p1, P p2)
    {
        System.Console.WriteLine("P ==");
        return new C();
    }
    public static C operator !=(P p1, P p2)
    {
        System.Console.WriteLine("P !=");
        return new C();
    }
}

我们需要超载两者== and !=同时在C#中。覆盖Equals and GetHashCode是一个好主意,但不是必需的,并且该程序中没有任何内容是好主意,因此我们将跳过它。

好的,现在我们有了if (something_of_type_C && T()),并且自从C is not bool,我们需要重写&&操作员。但 C# 不允许你重写&&直接操作员。让我们离题一下,谈谈语义&&。对于返回布尔值的函数A and B,语义bool result = A() && B(); are:

bool a = A();
bool c;
if (a == false) // interesting operation
  c = a;
else
{
  bool b = B(); 
  c = a & b;    // interesting operation
}
bool r = c;

所以我们生成三个临时的,a, b, and c,我们评估左侧A(),我们检查是否a是假的。如果是,我们就使用它的值。如果不是,我们计算B()然后计算a & b.

该工作流程中唯一的两个操作是特定于 bool 类型 are 检查是否虚假 and 非短路&,所以*这些是在用户定义的操作中重载的操作&&。 C# 要求您重载三个操作: 用户定义&,用户定义“我是真的吗?”和用户定义的“我是假的吗?”。 (喜欢== and !=,最后两个必须成对定义。)

现在,一个明智的人会写operator true and operator false所以他们总是表现出相反的态度。今天我们不是明智的人:

class C
{
    public static bool operator true(C c)
    {
        System.Console.WriteLine("C operator true");
        return true;
    }

    public static bool operator false(C c)
    {
        System.Console.WriteLine("C operator false");
        return true; // Oops
    }

    public static C operator &(C a, C b)
    {
        System.Console.WriteLine("C operator &");
        return a;
    }
}

请注意,我们还要求用户定义&拿两个Cs 并返回 aC,确实如此。

好吧,所以,回想一下我们有

if (p != null && T())

and p != null属于类型C。所以我们现在必须将其生成为:

C a = p != null; // Call to P.operator_!=
C c;
bool is_false = a is logically false; // call to C.operator_false
if (is_false) 
  c = a;
else
{
  bool b = T();
  c = a & b; // Call to C.operator_&
}

但现在我们有一个问题。operator &需要两个Cs 并返回 aC,但我们有一个bool从返回T。我们需要一个C。没问题,我们将添加一个隐式的用户定义转换C from bool:

public static implicit operator C(bool b)
{
    System.Console.WriteLine("C implicit conversion from bool");
    return new C();
}

好的,现在我们的逻辑是:

C a = p != null; // Call to P.operator_!=
C c;
bool is_false = C.operator_false(a);
if (is_false)
  c = a;
else
{
  bool t = T(); 
  C b = t; // call to C.operator_implicit_C(bool)
  c = a & b; // Call to C.operator_&
}

请记住,我们的目标是:

if (c)
  System.Console.WriteLine("in the consequence");

我们如何计算这个? C# 的原因是如果你有operator true on C那么你应该能够在if只需调用即可获得条件operator true。完成后,最终我们得到了语义:

C a = p != null; // Call to P.operator_!=
C c;
bool is_false = C.operator_false(a);
if (is_false)
  c = a;
else
{
  bool t = T(); 
  C b = t; // call to C.operator_implicit_C(bool)
  c = a & b; // Call to C.operator_&
}
bool is_true = C.operator_true(c);
if (is_true) …

但正如我们在这个疯狂的例子中看到的,我们可以输入if不打电话T没问题前提是operator false and operator true两者都返回 true。当我们运行该程序时,我们得到:

P !=
C operator false
C operator true
in the consequence

一个明智的人永远不会编写这样的代码:C被同时认为是对的和假的,但是像我今天这样不懂事的人可以,并且编译器知道,因为我们设计的编译器是正确的不管程序是否合理。

这就解释了为什么if (p != null && T(out s))s可以在结果中取消分配。如果p is dynamic那么编译器的原因是“p在运行时可能是这些疯狂类型之一,在这种情况下我们不再使用bool操作数,因此s可能不会被分配”。

这个故事的寓意是:dynamic使编译器极其保守关于可能发生的事情;它必须假设最坏的情况。在这种特殊情况下,必须假设p != null might not是一个空引用检查并且可能not be bool, 然后operator true and operator false可能都会返回true.

那么,这是一个合法的错误吗(我使用的是 C# 7.0)?

编译器的分析是正确的——相信我,这不是一个容易编写或测试的逻辑。

您的代码有错误;修理它。

我应该如何处理这个问题?

如果您想对某个对象进行空引用检查dynamic,你最好的选择是:如果这样做会让你感到疼痛,那就不要这样做。

抛弃了dynamic并回到object, and then进行引用相等性检查:if (((object)p) == null && …

或者,另一个不错的解决方案是使其非常明确:if (object.ReferenceEquals((object)p, null) && …

这些是我首选的解决方案。更糟糕的解决方案是将其分解:

if (p != null)
  if (T(out string s))
     consequence

现在没有了operator &即使在最坏的情况下也会打电话。请注意,在这种情况下,我们仍然可能处于这样的情况:p != null是真的并且p为空,因为没有什么可以阻止任何人超载!=无论其操作数如何,始终返回 true。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检测未分配的局部变量的错误(当动态变量影响代码流预测时) 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲

随机推荐

  • 设置自定义异常处理程序时,error_get_last() 在 PHP 7 中返回 NULL

    好吧 这花了一些时间来打破它 这里是 有一个包含错误的脚本 本文的其余部分如下 错误 php
  • 折叠表达式:替换特定类型但转发所有其他类型,如何正确特化 `std::forward`?

    我试图替换折叠表达式中的特定类型 同时简单地转发所有其他类型 但失败了 模拟std forward 实际上复制了 GCC 的实现 只是添加了一些输出来看看发生了什么 namespace test template
  • mysql group_concat 对多个字段进行分组

    我有一个表成员member id member name club name region zone email作为字段 我正在使用MySQLgroup concat功能类似于 SELECT group concat distinct m
  • 如何从多个 GUI 类集成多页 Java 桌面应用程序

    我正在开发一个 Java Swing 桌面应用程序项目 该应用程序大约有 15 个 GUI 页面 我可以使用分层窗格和选项卡式窗格将所有 GUI 组件放在一个类中 但这个班级将会很大 如果我可以将项目分成几个较小的子项目 并让每个子项目都有
  • 如何在每次音量为零时使用 ffmpeg 分割 mp4 视频?

    我需要将一个视频分割成许多较小的视频 我尝试过 PySceneDetect 它的 2 种场景检测方法不符合我的需要 这个想法是在每次音量非常低 每次音频电平小于给定参数时触发场景切换 中断 我认为总体 RMS dB 音量水平就是我的意思 目
  • Java程序:需要YYYY-MM-DD格式的当前日期,而没有日期数据类型的时间[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我只需要 yyyy mm dd 格式的日期 因为 DB2 表的日期列精度为 10 Dat
  • 在 WM_SIZE 之后调整渲染目标 Direct2D 的大小

    快速问一下大家 我目前正在使用 Directx3D 和 2D 我想知道在调整 Windows 大小时是否必须重新创建渲染目标 或者 Direct2D 会自动检测到这一点 因为它绑定到 DXGISurface 交换链 当我创建它时 这是我用来
  • Kafka流处理器线程安全吗?

    我知道这个问题之前在这里被问过 卡夫卡流并发 但这对我来说很奇怪 根据文档 或者也许我遗漏了一些东西 每个分区都有一个任务 意味着不同的处理器实例 并且每个任务都由不同的线程执行 但是当我测试它时 我发现不同的线程可以获得不同的处理器实例
  • 使用 PhantomJS 包含 js 文件

    在 PhantomJS 脚本中 我尝试加载定义数组的本地 JavaScript 文件 var webPage require webpage page webPage create injected page injectJs codes
  • 将 SupportMapFragment 放置在 DialogFragment 上

    我试图在 DialogFragment 上添加 SupportMapFragment 但它返回error inflating class fragment 我不明白为什么它会被退回error inflating class fragment
  • Zend 框架有文件结构的修复版本吗?

    作为 Zend 框架的新手 我对该框架有一些与版本相关的问题 Zend Framework 是否有固定的文件结构 即文件布局的固定形式 如果是这样 这个文件结构是否会根据框架版本而变化 如果是这样 是否有任何参考资料可以了解文件结构的所有差
  • R 中的对数概率图?

    Does anyone know how to create log probability plot like this one in R where the x axis is probability and y axis is in
  • ListFragment 作为 DialogFragment

    是否可以显示ListFragment as Dialog 或者没有办法 我应该实现我自己的ListView empty TextView和不确定的ProgressBar inside DialogFragment myself 另外一个选择
  • 关于“self”关键字

    void Foo void Foo 在该方法中 void Foo 关键字self表示该类的一个实例 但在方法中 void Foo 关键字是什么self意思是 这是否意味着Class self是每个方法的两个隐式参数之一 它是一个指向对象的指
  • 使用 SQLAlchemy 的 sql.func 注册自定义函数

    如何在 sqlalchemy 中应用自定义过滤器 我尝试过 hybrid property 和 hybrid method 然而 他们给出了错误 这是我的代码 class Product db Model tablename product
  • 每天在 Swift 中重置 NSUserDefault 键

    我正在编写一个应用程序 需要每天重置存储在 NSUserDefaults 中的密钥 00 00 时 我已经实现了这一目标 但我使用的方法是一种混乱且不可靠的方法 有没有简单的方法可以实现我的目标 这是代码 extension NSDate
  • WooCommerce 在结帐时使用 Optgroup 选择下拉菜单

    我在用着WordPress 5 0 2 with WooCommerce 3 5 3我在结帐页面上创建了一个选择下拉菜单 效果很好 但是我想在其中添加一些选项组来组织选择选项 这是我的代码函数 php add action woocomme
  • WatchKit 扩展包 ID 不可用

    我已将手表套件应用程序添加到我的 iOS 应用程序中 一切工作正常且运行良好 直到我想在两个应用程序之间共享数据 每当我尝试在手表套件扩展上添加 应用程序组 功能时 它都会告诉我我的捆绑包 ID com myrealappid watchk
  • 虚拟子域:每个用户一个子域

    在我的网站上 我使用虚拟主机 因此我的用户可以拥有虚拟域 如 user1 mydomain com user2 mydomain com 等 问题是 在 user1 domain com 等虚拟域上 索引页面始终与我的索引页面 http m
  • 检测未分配的局部变量的错误(当动态变量影响代码流预测时)

    文档意味着 out 参数在发送到函数之前不需要初始化 只需声明 然而 这段代码 class Program static void Main dynamic p string s if p null T out s System Conso