C# 方法的数据类型 问题:

C# 方法的数据类型 问题:,c#,function,methods,types,C#,Function,Methods,Types,委托如何存储对函数的引用?源代码似乎将其称为对象,并且它调用方法的方式似乎是根据源代码修改的。有人能解释一下C#是如何处理这件事的吗 原职 似乎我一直在与C#强加给程序员的抽象概念作斗争。让我恼火的是函数/方法的混淆。据我所知,所有方法实际上都是分配给类属性的匿名方法。这就是为什么没有函数以数据类型作为前缀的原因。例如 void foo() { ... } 。。。将用Javascript编写为 Function foo = function():void { ... }; 根据我的经验,匿

委托如何存储对函数的引用?源代码似乎将其称为对象,并且它调用方法的方式似乎是根据源代码修改的。有人能解释一下C#是如何处理这件事的吗


原职 似乎我一直在与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 body
    return 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 method
    StaticMethod
    from class
    Example
    ”时,它首先查找已编译方法的内部缓存。当没有匹配项(这意味着这是该方法的第一次调用)时,运行时会要求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