草庐IT

c# - 隐式 (bool) 和 == 运算符覆盖 - 正确处理 if 语句

coder 2024-05-25 原文

我有一个自定义类,它实现了 bool 运算符的 ==implicit

这是处理所有可能的 if ==/!= 语句并获得预期结果的正确方法吗? 像这样:

public class Foo
{
    public bool Result { get; set; }

    public static bool operator ==(bool @bool, Foo foo)
    {
        return Equals(foo, @bool);
    }
    public static bool operator !=(bool @bool, Foo foo)
    {
        return NotEquals(foo, @bool);
    }
    public static bool operator ==(Foo foo, bool @bool)
    {
        return Equals(foo, @bool);
    }
    public static bool operator !=(Foo foo, bool @bool)
    {
        return NotEquals(foo, @bool);
    }
    public static bool operator ==(Foo foo, Foo fooB)
    {
        return Equals(foo, fooB);
    }
    public static bool operator !=(Foo foo, Foo fooB)
    {
        return NotEquals(foo, fooB);
    }
    public static implicit operator bool(Foo foo)
    {
        try { return foo.Result; }
        catch { return false; }
    }

    private static bool Equals(Foo foo, Foo fooB)
    {
        if (object.Equals(foo, null))
        {
            if (object.Equals(fooB, null))
                return true;

            return false;
        }

        if (object.Equals(fooB, null))
            return false;

        return foo.Result == fooB.Result;
    }
    private static bool NotEquals(Foo foo, Foo fooB)
    {
        if (object.Equals(foo, null))
        {
            if (object.Equals(fooB, null))
                return false;

            return true;
        }

        if (object.Equals(fooB, null))
            return true;

        return fooB.Result != foo.Result;
    }
    private static bool Equals(Foo foo, bool @bool)
    {
        if (object.Equals(foo, null))
            return true;

        return @bool == foo.Result;
    }
    private static bool NotEquals(Foo foo, bool @bool)
    {
        if (object.Equals(foo, null))
            return false;

        return @bool != foo.Result;
    }

}

我特别想知道你似乎真的需要为其中任何一个实现重载

if (new Foo() != true)

if (true != new Foo())

最佳答案

我觉得你写的代码太多:-)

以下就足够了:

public class Foo
{
    public bool Result { get; set; }

    public static implicit operator bool(Foo foo)
    {
        return !object.ReferenceEquals(foo, null) && foo.Result;
    }
}

然后编译器将知道如何将 Foo 类型的变量隐式转换为 bool。 (并且 null 将被转换为 false)。

所以,当你写:

new Foo() == false

编译器将使用隐式类型转换器从 Foo 中获取一个 bool 值,然后对 bool 使用标准相等运算符。

如果我们查看编译器为该表达式生成的 IL,我们会发现:

newobj instance void FooBool.Foo::.ctor()               // new Foo()
call bool FooBool.Foo::op_Implicit(class FooBool.Foo)   // implicit operator (Foo => bool)
ldc.i4.0                                                // false
ceq                                                     // equality operator (bool)

这是一个测试:

static void Main(string[] args)
{
    AssertTrue(new Foo() == false);
    AssertTrue(false == new Foo());
    AssertFalse(new Foo() != false);
    AssertFalse(false != new Foo());
    AssertTrue(new Foo { Result = true } == true);
    AssertTrue(true == new Foo { Result = true });
    AssertFalse(new Foo { Result = true } != true);
    AssertFalse(true != new Foo { Result = true });
}

static void AssertTrue(bool value)
{
    Console.WriteLine(value ? "ok" : "not ok");
}

static void AssertFalse(bool value)
{
    Console.WriteLine(value ? "not ok" : "ok");
}

它为每个测试打印ok。因此,如果我理解正确的话,这个简化的代码应该可以满足您的需求。

更新

要允许相等运算符对 Foo(可能为 null)的实例起作用:

public static bool operator ==(Foo a, Foo b)
{
    if (object.ReferenceEquals(a, b))
    {
        return true;
    }
    else if (object.ReferenceEquals(a, null))
    {
        return !b.Result;
    }
    else if (object.ReferenceEquals(b, null))
    {
        return !a.Result;
    }
    else
    {
        return a.Result == b.Result;
    }
}

然后您还应该实现不等式运算符:

public static bool operator !=(Foo a, Foo b)
{
    return !(a == b);
}

同时覆盖 GetHashCode + Equals

public override int GetHashCode()
{
    return this.Result ? 1 : 0;
}

public override bool Equals(object obj)
{
    if (object.ReferenceEquals(obj, null))
    {
        return !this.Result;
    }

    Type t = obj.GetType();

    if (t == typeof(Foo))
    {
        return this.Result == ((Foo)obj).Result;
    }
    else if (t == typeof(bool))
    {
        return this.Result == (bool)obj;
    }
    else
    {
        return false;
    }
}

关于c# - 隐式 (bool) 和 == 运算符覆盖 - 正确处理 if 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21485644/

有关c# - 隐式 (bool) 和 == 运算符覆盖 - 正确处理 if 语句的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  5. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  6. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  9. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  10. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

随机推荐