草庐IT

c# - 隐式方法组转换陷阱(第 2 部分)

coder 2024-05-23 原文

this question 简化而来并消除了 LinqPad 可能产生的影响(没有冒犯性),这是一个像这样的简单控制台应用程序:

public class Program
{
    static void M() { }    
    static void Main(string[] args)
    {
        Action a = new Action(M);
        Delegate b = new Action(M);
        Console.WriteLine(a == b);      //got False here
        Console.Read();
    }        
}

上述代码的 CIL 中的运算符 ceq 导致“false”(有关详细信息,请访问原始问题)。所以我的问题是:

(1) 为什么 == 翻译成 ceq 而不是 call Delegate Equals

这里我不关心 Delegate 和 Action 之间的(un)wrapping。最后,在评估 a == b 时,a 是 Action 类型,而 b 是 Delegate。来自规范:

7.3.4 Binary operator overload resolution

An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

• The set of candidate user-defined operators provided by X and Y for the operation operator op(x, y) is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of §7.3.5. If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.

• If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. The predefined implementations of a given operator are specified in the description of the operator (§7.8 through §7.12).

• The overload resolution rules of §7.5.3 are applied to the set of candidate operators to select the best operator with respect to the argument list (x, y), and this operator becomes the result of the overload resolution process. If overload resolution fails to select a single best operator, a binding-time error occurs.

7.3.5 Candidate user-defined operators

Given a type T and an operation operator op(A), where op is an overloadable operator and A is an argument list, the set of candidate user-defined operators provided by T for operator op(A) is determined as follows:

• Determine the type T0. If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.

• For all operator op declarations in T0 and all lifted forms of such operators, if at least one operator is applicable (§7.5.3.1) with respect to the argument list A, then the set of candidate operators consists of all such applicable operators in T0.

• Otherwise, if T0 is object, the set of candidate operators is empty.

• Otherwise, the set of candidate operators provided by T0 is the set of candidate operators provided by the direct base class of T0, or the effective base class of T0 if T0 is a type parameter.

从规范来看,a 和 b 具有相同的基类 Delegate,显然应该应用 Delegate 中定义的运算符规则 ==此处(运算符 == 本质上调用 Delegate.Equals)。但是现在看起来用户定义运算符的候选列表是空的,最后 Object == 被应用了。

(2) FCL 代码是否应该(是否)遵守 C# 语言规范?如果不是,我的第一个问题就没有意义,因为有些东西是经过特殊处理的。然后我们可以用“哦,这是 FCL 的特殊待遇,他们可以做我们做不到的事情。该规范是针对外部程序员的,别傻了”来回答所有这些问题。

最佳答案

编译器与委托(delegate)的工作方式非常不同且不寻常。有很多隐式处理。 请注意,本指南中的“通用基本类型”规则适用于“用户定义的运算符”。委托(delegate)是内部的和系统的。例如,您可以编写 Action a = M; 而不是 Action a = new Action(M);。您可以在之后添加 a += M;。看看CIL发生了什么,第一时间很有趣。

此外:比较代表是危险且重要的。每个委托(delegate)实际上都是多播委托(delegate)。您可以将多个函数指针添加到同一个委托(delegate)。委托(delegate) [L(); M(); N();] 等于委托(delegate) [M();] ?函数指针包含类实例(例如方法)。 [a.M();] 是否等于 [b.M();]?这一切都取决于案例,比较实现需要遍历调用列表。

Delegates 从通用基类型 Delegate 继承是隐式的,你可能会在其他场景中遇到这个问题,例如泛型约束:您不能将 Delegate 指定为泛型参数 T 的约束。此处编译器明确拒绝这一点。创建自己的类也是如此,继承自 Delegate。

这是对两个问题的回答——“Delegate”不是纯粹的 FCL,它与编译器紧密耦合。如果您真的想要 Microsoft 的委托(delegate)比较器行为 - 只需显式调用 Equals(a, b)

关于c# - 隐式方法组转换陷阱(第 2 部分),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8939350/

有关c# - 隐式方法组转换陷阱(第 2 部分)的更多相关文章

  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-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  5. 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

  6. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  7. Ruby 方法() 方法 - 2

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

  8. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  9. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  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

随机推荐