C# 方法的数据类型 问题:
委托如何存储对函数的引用?源代码似乎将其称为对象,并且它调用方法的方式似乎是根据源代码修改的。有人能解释一下C#是如何处理这件事的吗C# 方法的数据类型 问题:,c#,function,methods,types,C#,Function,Methods,Types,委托如何存储对函数的引用?源代码似乎将其称为对象,并且它调用方法的方式似乎是根据源代码修改的。有人能解释一下C#是如何处理这件事的吗 原职 似乎我一直在与C#强加给程序员的抽象概念作斗争。让我恼火的是函数/方法的混淆。据我所知,所有方法实际上都是分配给类属性的匿名方法。这就是为什么没有函数以数据类型作为前缀的原因。例如 void foo() { ... } 。。。将用Javascript编写为 Function foo = function():void { ... }; 根据我的经验,匿
原职 似乎我一直在与C#强加给程序员的抽象概念作斗争。让我恼火的是函数/方法的混淆。据我所知,所有方法实际上都是分配给类属性的匿名方法。这就是为什么没有函数以数据类型作为前缀的原因。例如
void foo() { ... }
。。。将用Javascript编写为
Function foo = function():void { ... };
根据我的经验,匿名函数通常是不好的形式,但在这里,它在整个语言标准中都很丰富。由于您无法使用其数据类型定义函数(显然,隐含/处理由编译器承担),如果从未声明类型,如何存储对方法的引用
我正努力避免和它的变体(&),因为
对象
(参见第23-25行)
如果这些真的是对象,我们如何称呼它们?根据
delegate.cs
trail,它在以下路径上死了:
Delegate.cs:DynamicInvoke()
这并不能解释如果方法确实是一个对象,它是如何被调用的。感觉好像这根本不是代码,实际调用的代码已经从源代码库中编辑好了
谢谢你的帮助
对以前评论的答复
@艾米:我在那句话之后马上举了个例子来解释我的意思。如果函数以数据类型作为前缀,则可以编写真正的匿名函数,并将其作为属性存储到对象中,例如:
private Dictionary<string, Function> ops = new Dictionary<string, Function> {
{"foo", int (int a, int b) { return a + b } }
};
private Dictionary ops=新字典{
{“foo”,int(inta,intb){返回a+b}
};
就目前而言,C#不允许您编写真正的匿名函数,也不允许您在后面和后面编写该函数
@500内部服务器错误:我已经解释了我要做的事情。我甚至大胆了。你认为这里有任何不可告人的动机;我只是想了解C#如何存储对方法的引用。我甚至提供了源代码的链接,以便其他人可以自己阅读代码并帮助回答问题
@辩证法:显然,如果我已经在谷歌上找到了典型的答案,那么唯一能找到我要找的答案的地方就是这里。我意识到这超出了大多数C#开发人员的知识范围,因此我提供了源代码链接。如果你不知道答案,你不必回复。虽然我不完全理解你对“真正的匿名函数”、“不以数据类型为前缀”等的见解,但我可以向你解释如何用C#call方法编写应用程序
首先,C#中没有这样的“函数”。C#中的每个可执行实体实际上都是一个方法,也就是说,它属于类。即使您定义lambda或匿名函数,如下所示:
collection.Where(item => item > 0);
C#编译器在后台创建编译器生成的类,并将lambda bodyreturn item>0
放入编译器生成的方法中
假设你有这个代码:
class Example
{
public static void StaticMethod() { }
public void InstanceMethod() { }
public Action Property { get; } = () => { };
}
static class Program
{
static void Main()
{
Example.StaticMethod();
var ex = new Example();
ex.InstanceMethod();
ex.Property();
}
}
C#编译器将从中创建一个IL代码。IL代码不是立即可执行的,它需要在虚拟机中运行
IL代码将包含一个类Example
,该类包含两个方法(实际上是四个-默认构造函数和属性getter方法将自动生成)和一个编译器生成的类,该类包含一个方法,该方法的主体是lambda表达式的主体
Main
的IL代码如下(简化):
注意那些call
和callvirt
指令:这些是方法调用
要实际执行被调用的方法,需要将它们的IL代码编译成机器代码(CPU指令)。这发生在名为.NET运行时的虚拟机中。有几种,如.NETFramework、.NETCore、Mono等
NET运行时包含一个JIT(即时)编译器。它在程序执行期间将IL代码转换为实际可执行的代码
当.NET运行时第一次遇到IL代码“call methodStaticMethod
from classExample
”时,它首先查找已编译方法的内部缓存。当没有匹配项(这意味着这是该方法的第一次调用)时,运行时会要求JIT编译器使用IL代码创建这样一个已编译且准备运行的方法。IL代码被转换成一系列CPU操作并存储在进程的内存中。指向已编译代码的指针存储在缓存中,以备将来重用
这一切都将发生在call
或callvirt
IL指令后面(再次简化)
一旦发生这种情况,运行时就可以执行该方法了。CPU获取编译代码的第一个操作地址作为下一个要执行的操作,并继续执行,直到代码返回。然后,运行时再次接管并继续执行下一个IL指令
委托的DynamicInvoke
方法做了同样的事情:它指示运行时调用一个方法(在一些附加参数检查等之后)。您提到的“死胡同”RuntimeMethodHand
class Example
{
public static void StaticMethod() { }
public void InstanceMethod() { }
public Action Property { get; } = () => { };
}
static class Program
{
static void Main()
{
Example.StaticMethod();
var ex = new Example();
ex.InstanceMethod();
ex.Property();
}
}
call void Example::StaticMethod()
newobj instance void Example::.ctor()
callvirt instance void Example::InstanceMethod()
callvirt instance class [mscorlib]System.Action Example::get_Prop()
callvirt instance void [mscorlib]System.Action::Invoke()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApp1
{
class Program
{
private static Dictionary<string, Func<int, int, int>> FuncOps = new Dictionary<string, Func<int, int, int>>
{
{"add", (a, b) => a + b},
{"subtract", (a, b) => a - b}
};
//There are no anonymous delegates
//private static Dictionary<string, delegate> DelecateOps = new Dictionary<string, delegate>
//{
// {"add", delegate {} }
//};
private static Dictionary<string, dynamic> DynamicOps = new Dictionary<string, dynamic>
{
{"add", new Func<int, int, int>((a, b) => a + b)},
{"subtract", new Func<int, int, int>((a, b) => a - b)},
{"inverse", new Func<int, int>((a) => -a )} //Can't do this with Func
};
private static Dictionary<string, MethodInfo> ReflectionOps = new Dictionary<string, MethodInfo>
{
{"abs", typeof(Math).GetMethods().Single(m => m.Name == "Abs" && m.ReturnParameter.ParameterType == typeof(int))}
};
static void Main(string[] args)
{
Console.WriteLine(FuncOps["add"](3, 2));//5
Console.WriteLine(FuncOps["subtract"](3, 2));//1
Console.WriteLine(DynamicOps["add"](3, 2));//5
Console.WriteLine(DynamicOps["subtract"](3, 2));//1
Console.WriteLine(DynamicOps["inverse"](3));//-3
Console.WriteLine(ReflectionOps["abs"].Invoke(null, new object[] { -1 }));//1
Console.ReadLine();
}
}
}
delegate object CustomFunc(params object[] paramaters);
private static Dictionary<string, CustomFunc> CustomParamsOps = new Dictionary<string, CustomFunc>
{
{"add", parameters => (int) parameters[0] + (int) parameters[1]},
{"subtract", parameters => (int) parameters[0] - (int) parameters[1]},
{"inverse", parameters => -((int) parameters[0])}
};
Console.WriteLine(CustomParamsOps["add"](3, 2)); //5
Console.WriteLine(CustomParamsOps["subtract"](3, 2)); //1
Console.WriteLine(CustomParamsOps["inverse"](3)); //-3