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

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(使用前将#替换为@)

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

  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 未找到 Boost 库,但编译正常

    我正在尝试在 C 中使用 boost 的文件系统 使用时看起来编译没问题 c c Analyse c o Analyse o g W Wall L usr local lib lboost filesystem lboost system
  • 循环遍历 C 结构中的元素以提取单个元素的值和数据类型

    我有一个要求 我有一个 C 语言的大结构 由大约 30 多个不同数据类型的不同元素组成 typedef struct type1 element1 type2 element2 type3 element3 type2 element4 1
  • 当事件button.click发生时,如何获取按钮名称/标签?

    我以编程方式制作按钮并将它们添加到堆栈面板中 以便每次用户导航到页面时按钮都会发生变化 我正在尝试做这样的事情 当我单击创建的按钮时 它将获取按钮的标签并转到正确的页面 但是 我无法使用 RoutedEventHandler 访问按钮元素
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 强制初始化模板类的静态数据成员

    关于模板类的静态数据成员未初始化存在一些问题 不幸的是 这些都没有能够帮助我解决我的具体问题的答案 我有一个模板类 它有一个静态数据成员 必须为特定类型显式实例化 即必须专门化 如果不是这种情况 使用不同的模板函数应该会导致链接器错误 这是
  • cpp.react库的C++源代码中奇怪的“->* []”表达式

    这是我在文档中找到的 C 片段cpp react 库 https github com schlangster cpp react implicit parallelism auto in D MakeVar 0 auto op1 in g
  • RestSharp获取序列化输出

    我正在寻找一种方法来访问 AddBody 调用的序列化结果 我正在使用内置的 RestSharp 序列化器 例子 class Foo public string FooField void SendRecord var f new Foo
  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 即使没有异步,CallContext.LogicalGetData 也会恢复。为什么?

    我注意到CallContext LogicalSetData LogicalGetData不按照我期望的方式工作 内部设置的值async方法得到恢复即使没有异步或任何类型的线程切换 无论如何 这是一个简单的例子 using System u
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 在 VS 中运行时如何查看 C# 控制台程序的输出?

    我刚刚编写了一个名为 helloworld 的聪明程序 它是一个 C NET 4 5 控制台应用程序 在扭曲的嵌套逻辑迷宫深处 使用了 Console WriteLine 当我在命令行运行它时 它会运行并且我会看到输出 我可以执行其他命令并
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • Visual Studio 2015 - Web 项目上缺少共享项目参考选项卡

    我从 MSDN 订阅升级到 Visual Studio 2015 因为我非常兴奋地阅读有关共享项目的信息 当我们想要做的只是重用代码时 不再需要在依赖项中管理 21382 个 nuget 包 所以我构建了一个测试共享项目 其中包含一些代码
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点

随机推荐

  • 设置自定义异常处理程序时,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