jjzjj

c# - 将扩展方法组转换为具有泛型类型的委托(delegate)

coder 2024-05-25 原文

我在 IDataReader 上有两个具有以下签名的扩展方法:

internal static List<T> GetList<T>(this IDataReader reader, Func<string, T> del)

internal static double? GetDoubleOrNull(this IDataReader reader, string columnName)

GetDoubleOrNull 没有任何重载。

在其他地方,我可以做

Func<string, double?> del = reader.GetDoubleOrNull;

var x = reader.GetList(del);

var x = reader.GetList<double?>(reader.GetDoubleOrNull);

或者只是传入一个实例方法,比如

public double? blah(string s)

var x = reader.GetList(blah);

可是我做不到

var x = reader.GetList(reader.GetDoubleOrNull);

编译器报错

cannot convert from 'method group' to 'System.Func<string,double?>'

我不明白这个。我认为由于 GetDoubleOrNull 没有重载,所以不会有重载解析,它可以从方法签名中推断出类型参数。

真正令人困惑的部分是它在传入 blah 时似乎如何工作。

最佳答案

前言:如果您需要完整的解释,请跳至编辑部分。剧透:扩展方法是一种编译器技巧,实际上比调用它们时看起来多了一个参数

在方法组的解析中。显然,C# 编译器不会花时间判断您使用的方法是否有重载;它总是需要显式转换。查看:

What is a method group in C#?
Method Inference does not work with method group

reader.GetDoubleOrNull返回的方法组根据您尝试将其转换到的内容缩小范围:GetDoubleOrNull可以使用该名称引用任意数量的重载方法。您必须显式转换它。

有趣的是,出于同样的原因,您甚至不能将方法组分配给隐式类型变量:

var x = reader.GetDoubleOrNull;

编译失败,因为它需要显式转换。

编辑 我很确定这里的混淆与扩展方法有关:

查看以下测试类:

public static class Extensions
{
    public static List<T> GetList<T>(this IDataReader reader, Func<string, T> del)
    {
        throw new NotImplementedException();
    }

    public static double? GetDoubleOrNull(this IDataReader reader, string columnName)
    {
        throw new NotImplementedException();
    }

    public static double? blah(this string s)
    {
        throw new NotImplementedException();
    }
}

可以调用成功

var x = reader.GetList(Extensions.blah);

为什么会这样blah也是静态扩展方法,因此,根据您的证据,上面的行似乎不应该编译。让事情变得更复杂,让我们添加这个方法:

public static List<T> GetList2<T>(this IDataReader reader, Func<IDataReader, string, T> del) 
{ 
    throw new NotImplementedException(); 
}

你现在可以调用

x = reader.GetList2(Extensions.GetDoubleOrNull);

它会正确编译。给了什么?

答案是:扩展方法实际上不会向您的对象添加方法。它们实际上是一种编译器技巧,让您可以像这些方法的一部分一样进行编程你的类(class)。来自 here :

In your code you invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates your code into a call on the static method. Therefore, the principle of encapsulation is not really being violated. In fact, extension methods cannot access private variables in the type they are extending.

所以,当你调用

var x = reader.GetDoubleOrNull("myColumnName");

实际上被编译和执行的基本上是这样的(一个完全合法的调用,即使它是一个扩展方法):

var x = Extensions.GetDoubleOrNull(reader, "myColumnName");

因此,当您尝试使用 GetDoubleOrNull作为 Func<string, double?> 的参数,编译器将“我可以将 GetDoubleOrNull 变成 Func<IDataReader, string, double?>,因为它有两个参数,但我不知道如何将它变成 Func<string, double?>

即使您将其称为 IDataReader 的实例方法也是如此对于一个参数,它不是:它只是一个具有两个参数的静态方法,C# 编译器欺骗您认为它是 IDataReader 的一部分.

关于c# - 将扩展方法组转换为具有泛型类型的委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9601514/

有关c# - 将扩展方法组转换为具有泛型类型的委托(delegate)的更多相关文章

  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 - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

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

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

  8. Ruby 方法() 方法 - 2

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

  9. 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]

  10. 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[

随机推荐