【问题标题】:Pass method as argument without Delegate将方法作为参数传递而不使用委托
【发布时间】:2019-10-23 15:13:30
【问题描述】:

C# 编译器是否需要函数委托才能将函数作为参数传递给另一个函数?

在 Visual Basic .Net 中,我可以将返回值与方法参数类型相同的函数传递给方法本身,而无需任何花哨的东西。除非该方法被编写为接受函数委托,否则这在 C# 中似乎是不可能的??

工作vb:

Function DoSomething(r As DataRow())
        '...
End Function

Function CallSomething()
        Dim dt As DataTable
        DoSomething(dt.Select(""))
End Function

C# 将要求调用代码分配一个变量并传递它,或者引用函数的签名包含一个委托(了解有用)。细微的差别,但我希望用一种语言进行的简单方法调用可以在另一种语言中同样容易地进行,因为它们都编译为相同的 IL。

这是我试图做的 C# 等价物:

string DoSomething(ref DataRow[] r)
{ ///do something }

void CallSomething()
{
    DataTable dt;
    DoSomething(ref dt.Select(""));
}

我所说的“花哨”是指委托的使用,我已经将委托用于更复杂的场景,例如将事件处理程序分配给数组元素,但我很惊讶他们会被要求这样做。

感谢您的回复。 VB 代码按预期运行,ByRef 在 VB 中是隐式的,您不能传递在堆 byval 上管理的对象。尽管如此,这是我可以在 VB 中提供的最简单的表单,如果您使用带有单个列表框的简单表单项目并将此代码放入,应该可以正常工作:

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Dim dt As New DataTable("A really great table")
        dt.Columns.Add("Column1", GetType(String))
        dt.Rows.Add("Row1") : dt.Rows.Add("Row2")
        PutRowsInListbox(dt.Select(""))
    End Sub

    Private Function PutRowsInListbox(ByRef r() As DataRow)
        For i As Integer = 0 To r.Length - 1
            Me.ListBox1.Items.Add(r(i).Item("Column1"))
        Next
    End Function
End Class

【问题讨论】:

  • 在您的 VB 代码中,r 或 dt.Select("") 看起来不像是函数委托,它们看起来像值。
  • 您能否添加一些您希望工作的 C# 代码示例,而无需做“任何花哨的事情”?
  • 我相信你应该能够做到public void CallSomething() { var dt = new DataTable(); DoSomething(dt.Select(""));}和public void DoSomething(DataRow[] r){}
  • 我认为 VB 并没有像你想象的那样做......
  • 您的 Vb.Net 代码不等同于您的 c# 代码。如果想让它们等价,则需要去掉c#代码上的ref关键字(或者VB.Net代码上加上ByRef)。

标签: c# .net vb.net parameters


【解决方案1】:
  1. 您的 Vb.Net 代码不等同于您的 c# 代码。如果想让它们等价,需要去掉c#代码上的ref关键字(或者VB.Net代码上加上ByRef)。

  2. Visual Basic 和 C# 都允许这种编程风格。但是请注意,您不是在此处将函数(或方法)传递给另一个方法,而不是在 Vb 或 c# 中 - 您只是用数据表的 Select 方法的结果填充 DataRow 数组。

  3. 1234563更多的是个人喜好。
  4. 您在问题中的 c# 代码示例将无法编译。

这是您现在拥有的 Vb.Net 代码的等效且可编译的 c# 版本:

void DoSomething(DataRow[] r)
{ 
    //do something 
}

void CallSomething()
{
    DataTable dt = null;
    DoSomething(dt.Select(""));
}

当然,除非您使用值而不是 null 实际初始化 dt,否则会抛出 NullReferenceException。

顺便说一句,ByRef 不是隐含的。传递引用类型并不意味着通过引用传递它们。这是一个常见的误解。

当您将引用类型传递给方法时,实际发生的是您通过值传递引用本身。如果您尝试在方法内重新分配引用,您可以自己轻松测试它 - 如果您没有指定 ByRef,您仍然会在方法外看到旧值。

【讨论】:

  • 感谢您的回复 - 这行得通。不过,关于 ByRef - 无论是否指定 ByRef,该测试在 VB 中都会产生相同的结果。我不会假装我知道 C# 'Ref' 是做什么的......
  • @ZoharPeled 您的演示并不能说明全部情况。是的,省略 ByRef/ByVal 意味着 ByVal,而不是 ByRef。但即使ByVal 仍然会为您提供原始对象,尽管是对它的引用的副本。所以你仍然可以修改原始对象,但是一旦你修改了副本的引用(即分配 New),你就不能了。但是传递一个对象ByVal 仍然更像是传递一个值类型的ByRef 而不是ByVal。见my demo
  • 除非指定了ByRef(c# 中的ref),否则一切都是按值传递的。传递值类型时,值本身被复制到参数中,而当传递引用类型时,引用被复制到参数中。这意味着您有两个指向同一个实例的引用 - 自然,每个引用都会看到另一个的更改。当传递ByRef 时,不会分配新的内存——而是该方法使用传递给它的值。这就是为什么当您使用ByRef 时,可以从方法外部看到更改。 jonskeet.uk/csharp/parameters.html
  • @djv 抱歉,忘记联系您了。请阅读上面的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 2011-05-29
  • 2016-02-06
  • 1970-01-01
  • 2023-03-05
  • 2013-11-17
相关资源
最近更新 更多