首页 新闻 会员 周边

C#值类型方法调用

1
悬赏园豆:100 [已解决问题] 解决于 2013-11-13 11:10

当在引用类型中调用方法时,会通过引用类型对象的类型对象指针,找到类型对象,从而找到对应的方法表中的方法。

 

在值类型中没有类型对象指针,那么值类型对象是如何找到相应的实例方法并调用的呢?

比如

struct Point

{

public int x;

public int y;

public int Add()

{

return x+y;

}

}

 

 

//调用

var p=new Point(){x=3,y=5};

p.Add();         //CLR如何寻找到该方法?

DongDong_GoAHead的主页 DongDong_GoAHead | 初学一级 | 园豆:114
提问于:2013-11-07 10:28
< >
分享
最佳答案
0

值类型实例不涉及到方法表操作,调用过程略显复杂,具体可以参考这篇博客

http://www.cnblogs.com/yangecnu/archive/2013/02/22/Value_Type_Internal.html

收获园豆:50
林J | 菜鸟二级 |园豆:202 | 2013-11-07 16:39
其他回答(9)
0

直接实例化结构调用方法就是了啊

dfgf | 园豆:206 (菜鸟二级) | 2013-11-07 11:48

方法随便调用,我问的是CLR是如何做到的?

即CLR是如何寻找到结构类型的方法入口的?

支持(0) 反对(0) DongDong_GoAHead | 园豆:114 (初学一级) | 2013-11-07 12:14
0

这是IL代码 调用方法的描述符....我也不是太懂 帮不到你

给你推荐一本书吧  你必须知道的.net  这本书 里面对值类型和应用类型的内存分配 有详细的讲解 或许可以得到你想要的答案

收获园豆:5
wolfy | 园豆:2636 (老鸟四级) | 2013-11-07 13:05
0

值类型在栈中,

引用在堆中.

而一个程序域中的情况无论什么类型,都进行描述.

收获园豆:5
迅捷网络[来送福利] | 园豆:576 (小虾三级) | 2013-11-07 13:52
1

LZ 这个问题提得太好了,让我花了一个中午找了好多资料,接触了很多新的知识,还与别人交流了意见,大致的结果如下,如有不对还望指出~谢谢啦~

先通过C# 代码与 IL代码来看

    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();
            MyStruct myStruct = new MyStruct();
            myStruct.PrintName("Zery");
        }
    }

    struct MyStruct
    {
        public  void PrintName(string name)
        {
            Console.WriteLine(name);
        }
    }
    internal class test
    {
        public void PirntName()
        {
        }
    }

IL 只列出关键部分

.locals init (class StructDemo.test V_0,
valuetype StructDemo.MyStruct V_1)
IL_0000: nop
IL_0001: newobj instance void StructDemo.test::.ctor()
IL_0006: stloc.0
IL_0007: ldloca.s V_1
IL_0009: initobj StructDemo.MyStruct
IL_000f: ldloca.s V_1
IL_0011: ldstr "Zery"
IL_0016: call instance void StructDemo.MyStruct::PrintName(string)

 

在执行Main这个方法时 会在线程栈的栈顶开辟一个Records Frame 的内存空间(此内存空间内的数据不遵循FILO原则)

现在看IL的第一条指令.locals init (class StructDemo.test V_0,valuetype StructDemo.MyStruct V_1)

定义了两个参数V_0与V_1类型分别为 test 和MyStruct类型

IL_0001: newobj instance void StructDemo.test::.ctor()

IL_0006: stloc.0

这两条进行实例化分配了内存空间并把指向堆中的地址赋值给了V_0,而我认为这个实例中应该是包含了方法的地址,

所以在实例调用方法时会与结构的实例调用方法一致,会有如下指令

IL_0016: call instance void StructDemo.MyStruct::PrintName(string) 注意是intance 实例的意思,只不过我用的结构的IL指令,实际上类的指令只是void StructDemo.MyStruct::PrintName(string)这一段会不一样而以,这个并不影响我们,

从上可以得出类的实例是包含了方法的地址的,所以可以调到方法 那结构呢?

从IL的指令上来说

IL_0007: ldloca.s V_1
IL_0009: initobj StructDemo.MyStruct

也是实现 实例化然后赋值给V_1

然后调用结构的方法

IL_0016: call instance void StructDemo.MyStruct::PrintName(string)

可以看到也是通过实例来调用的,也就是说结构的实例也有包含方法的址

 

但是我自己还是有点问题没有理解透

1 结构与类的方法是存在哪里的,是否类与结构都在各自的内存区域有一块方法表,用于存储方法,

2 自己还表达不出自己的问题。。。。。。

LZ如果对IL 不太了解 我有写过三篇IL的文章可供参考 

读懂IL代码就这么简单(一)

以上为个人见解,如有不对还望指正~

收获园豆:30
Zery | 园豆:6151 (大侠五级) | 2013-11-07 14:21

在IL层值类型和引用类型对于方法的调用是没区别的,在IL层两者都已经找到了方法的地址,要想知道区别,得更底层一点。

支持(0) 反对(0) 林J | 园豆:202 (菜鸟二级) | 2013-11-07 16:40
0

一个变量包含3个部分:变量名、数据类型、值;程序编译后,所有变量名都会被替换为内存地址;结构和类一样,元数据会加载到内存中的LoaderHeap,其中包含有方法表(此时,数据类型也被替换为内存地址了);值与类型的对应关系应该是由编译器来维护的。期待楼下修正与补充……

晚上回去继续研究

nianhua11 | 园豆:736 (小虾三级) | 2013-11-07 15:04
0

是这样的,只要是一个类型,都会在应用程序域的一个堆上分配一块空间,这块空间是当第一次使用这个类型时分配的,这叫做类型的类型,同时静态变量(static)也是在此时进行分配的,这块内存空间记录了这个类型所有的静态变量和方法地址。当对象进行实例化,会有一个地址指向这个类型的类型对应的空间,当进行某个方法调用时,就可以找到这个方法的地址,这和你实例化的对象是分配在栈(值类型)上还是分配在堆(引用类型)上没有关系。

收获园豆:5
ocean | 园豆:824 (小虾三级) | 2013-11-07 21:59
0

那我也有个问题,在创建对象的时候为类中成员去分配内存空间,那么方法是否也在这个时候被分配了内存空间呢?还有值类型数据一般存储在栈上,引用类型数据一般存放在堆中,那么方法是存放在栈中还是堆中呢?求大神...

轻狂の书生 | 园豆:1042 (小虾三级) | 2013-11-09 19:16
0

值类型和引用类型的区别不是在于指针,每个变量都有指针的,之类型占的内存固定,而且少,在使用的时候直接把内存里的字节复制过去消耗也不会太大,引用类型往往占用的内存比较大,而且在使用的时候往往是当参数传来传去还想只控制一个对象,设计语言的时候就只给了一个地址。

收获园豆:5
贪心狸猫 | 园豆:872 (小虾三级) | 2013-11-09 21:29
0

这个估计要看内存分配了

netqiang | 园豆:405 (菜鸟二级) | 2013-11-12 15:39
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册