In. Net, all basic types are defined by struct. It is different from the reference Type and has its own characteristics. This BLOG starts with the definition of Value Type in ECMA335.
The types defined by Class are not necessarily reference types. In fact, the value type is not (for example, ValueType). The ValueType defined by Class containsBinning value type and associated packing type. (ECMA335 Partition I, 8.9.7)
- When a non-static method on ValueType is called, this pointer is a reference to a hosted instance, and it will call the associated packing method.
- The value type itself does not support interfaces, but its associated packing type will.
- The value type cannot be inherited.
- The base class of the packing type should not contain any fields.
- Unlike the reference type, the value type does not need to call the constructor when creating an instance. By default, it sets all fields to null or 0 Based on the type.
General rules for using the Struct type:
1. The default constructor without parameters cannot be defined.
1: public struct Employee
2: {
3: public string Name;
4:
5: public Employee(string name)
6: {
7: this.Name = name;
8: }
9:
10: public Employee()
11: {
12: }
13:
14: public void Run()
15: {
16: Console.WriteLine("HI, I am {0}", Name);
17: }
18: }
Error message: Structs cannot contain explicit parameterless constructors (Structs cannot contain the displayed no-argument structure)
2. Initialization is not allowed.
1: public struct Employee
2: {
3: public string Name = "Hello";
4: }
Error message: 'Roger. Testing. Employee. name': cannot have instance field initializers in structs (Structs cannot contain initialized fields)
3. the Read-Only status cannot be changed.
1: static readonly Employee emp = new Employee("Roger");
2:
3: public static void Main()
4: {
5: emp.Name = "New Roger";
6:
7: Console.Read();
8: }
Error message: Fields of static readonly field 'Roger. testing. testing. emp 'cannot be assigned to (Struct t in a static constructor or a variable initializer) the Struct of the readonly type cannot be assigned unlessStatic ConstructorOr the variable can be modified during initialization.
Example:
1: static readonly Employee emp = new Employee("Roger");
2:
3: public static void Main()
4: {
5:
6: Console.Read();
7: }
8:
9: static Testing()
10: {
11: emp.Name = "New Roger";
12: }
4. Cannot inherit
1: public struct Manager : Employee
2: {
3: public string Title;
4: }
Error message: Type 'Employee' is in the interface list but not the interface
5. Struct can inherit numerous interfaces
1: public struct Manager : IComparable, ICloneable
2: {
3:
4: #region IComparable Members
5:
6: public int CompareTo(object obj)
7: {
8: throw new NotImplementedException();
9: }
10:
11: #endregion
12:
13: #region ICloneable Members
14:
15: public object Clone()
16: {
17: throw new NotImplementedException();
18: }
19:
20: #endregion
21: }
6. StructLayout
Explanation: http://www.cnblogs.com/happyhippy/articles/717028.html
7. serialize Struct
1: public static byte[]
2: RawSerialize(object anything)
3: {
4: int rawsize =
5: Marshal.SizeOf(anything);
6: IntPtr buffer =
7: Marshal.AllocHGlobal(rawsize);
8: Marshal.StructureToPtr(anything,
9: buffer, false);
10: byte[] rawdata = new byte[rawsize];
11: Marshal.Copy(buffer, rawdata,
12: 0, rawsize);
13: Marshal.FreeHGlobal(buffer);
14: return rawdata;
15: }
8. Call an API
Explanation: http://www.yesky.com/165/1621165.shtml
Method call on Struct type
1: using System;
2: using System.Collections.Generic;
3:
4: namespace Roger.Testing
5: {
6: public class Testing
7: {
8: public static void Main()
9: {
10: Employee e = new Employee("www.xwang.org");
11: e.Run();
12:
13: Console.Read();
14: }
15: }
16:
17: public struct Employee
18: {
19: public string Name;
20:
21: public Employee(string name)
22: {
23: this.Name = name;
24: }
25:
26: public void Run()
27: {
28: Console.WriteLine("HI, I am {0}", Name);
29: }
30: }
31: }
Compile IL
1: .method public hidebysig static void Main() cil managed
2: {
3: .entrypoint
4: // Code size 26 (0x1a)
5: .maxstack 2
6: .locals init (valuetype Roger.Testing.Employee V_0)
7: IL_0000: ldloca.s V_0
8: IL_0002: ldstr "www.xwang.org"
9: IL_0007: call instance void Roger.Testing.Employee::.ctor(string)
10: IL_000c: ldloca.s V_0
11: IL_000e: call instance void Roger.Testing.Employee::Run()
12: IL_0013: call int32 [mscorlib]System.Console::Read()
13: IL_0018: pop
14: IL_0019: ret
15: } // end of method Testing::Main
As you can see
IL_0007: call instance void Roger. Testing. Employee:. Run ()
It is actually the first one called at the beginning .:).
I discussed it with my friends. Is it because every method call will produce a packing and then call the method?
As mentioned in the opening article, Struct's this pointer will point to the method in the memory, pass Struct as the first parameter to the method, and then execute it (you have not read it in the memory layout, no confirmation :)).
Int, double, and so on all belong to the value type category, so the calling method is the same.
Let's look at the composition of the method table in WINDBG.
WinDBG Run method code
10: 003>! DumpMT-md 001430bc
2 EEClass: 00141328
3 Module: 00142c4c
4 Name: MyStruct
5 mdToken: 02000003 (C: \ Users \ xwang \ Desktop \ StructMethod.exe)
6 BaseSize: 0xc
7 ComponentSize: 0x0
8 Number of IFaces in IFaceMap: 0
9 Slots in VTable: 7
10 --------------------------------------
11 MethodDesc Table
12 Entry MethodDesc JIT Name
135f835100 5f2166cc PreJIT System. ValueType. ToString ()
145f3a6920 5f216698 PreJIT System. ValueType. Equals (System. Object)
155f357b50 5f2166c0 NONE System. ValueType. GetHashCode ()
165f82f960 5f216650 PreJIT System. Object. Finalize ()
170014c04d 0014308c NONE MyStruct. get_Name ()
180014c051 00143098 NONE MyStruct. set_Name (System. String)
190014c055 001430a4 NONE MyStruct. Run ()
The method table contains the call of the RUN method, which further confirms the existence of an Associated Boxed Type.