jjzjj

c# - 为什么不能为这个通用的 Clamp 方法推断出类型?

coder 2024-05-20 原文

我正在编写一个表示 LED 的类。 r、g 和 b 的基本 3 个 uint 值在 0 到 255 范围内。

我是 C# 的新手,从 uint1 开始,它比我想要的 8 位大。在编写自己的 Clamp 方法之前,我在网上查找了一个并找到了 this great looking answer建议扩展方法。问题是它无法推断类型为 uint。为什么是这样?这段代码上写满了 uint。我必须明确指定类型才能使其正常工作。

class Led
{
    private uint _r = 0, _g = 0, _b = 0;

    public uint R
    {
        get
        {
            return _r;
        }
        set
        {
            _r = value.Clamp(0, 255); // nope

            _r = value.Clamp<uint>(0, 255); // works
        }
    }
}

// https://stackoverflow.com/a/2683487
static class Clamp
{
    public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
    {
        if (val.CompareTo(min) < 0) return min;
        else if (val.CompareTo(max) > 0) return max;
        else return val;
    }
}

1 一个错误,使用 byte 当然是正确的方法。但我仍然对问题的答案感兴趣。

最佳答案

其他答案是正确的,但这里有一个微妙的地方我认为应该特别指出。

通常在 C# 中,整数文字的类型是 int,但它可以隐式转换为常量在范围内的任何数字类型。因此,即使 int 不能隐式转换为 uint,赋值 myuint = 123; 也是合法的,因为 int 适合。

从这个事实很容易陷入错误的信念,即 int 文字可以在任何需要 uint 的地方使用,但您已经发现了为什么会有这种信念错误的。

类型推断算法是这样的。 (当然,这是一个巨大的简化;lambda 使这变得相当复杂。)

  • 计算参数的类型
  • 分析参数与相应形式参数之间的关系
  • 从该分析中推断出泛型类型参数的类型界限
  • 检查边界的完整性——每个泛型类型参数都必须有边界——和一致性——边界不能矛盾。如果推理不完整或不一致,则该方法不适用。
  • 如果推导类型违反了它们的约束,则该方法不适用。
  • 否则,将具有推导类型的方法添加到用于重载决议的方法集中。

然后,过载解决方案将候选集中的方法相互比较以找到最佳方法。

(请注意,当然没有考虑返回类型;C# 检查是否可以将返回类型分配给分配给它的任何内容重载决策选择了方法之后,而不是在重载期间分辨率。)

在您的情况下,类型推断在“验证是否存在一组一致的边界”步骤中失败。 T 绑定(bind)到 intuint。这是一个矛盾,因此该方法甚至从未添加到要考虑的重载决议的方法集中。 int 参数可转换为uint 的事实从未被考虑过;类型推理引擎仅适用于类型。

类型推断算法也不会在您的场景中以任何方式“回溯”;它没有说“好的,我无法为 T 推断出一致的类型,但也许其中一种类型有效。如果我同时尝试边界 intuint?我们可以看看它们中的任何一个是否真的产生了一种有效的方法。” (它确实做一些类似于涉及 lambda 的事情,这可能导致它在某些情况下尝试任意多种可能的类型组合。)如果推理算法以这种方式工作,那么您将得到结果你想要,但它没有。

基本上,这里的哲学是类型推断算法不是寻求找到使程序运行的任何方法,而是寻找关于派生唯一类型的类型的推理链从论证中得出的信息得出的逻辑结论。 C# 尝试按照用户的意思去做,但也尽量避免猜测;在这种情况下,而不是潜在地猜测错误,它要求您清楚您打算推断的类型。

关于c# - 为什么不能为这个通用的 Clamp 方法推断出类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32716631/

有关c# - 为什么不能为这个通用的 Clamp 方法推断出类型?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  6. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  7. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  8. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  9. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  10. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

随机推荐