7

如果您深入了解,C# 中的值类型会被编译器/CLR 非常特殊地处理。但是 CLR 内部的类型被更特殊地对待。这就是我的意思:

int a = 5;
int b = 10;
int с = a + b;
a.CompareTo(b);

您可以将鼠标悬停int在 Visual Studio 中,然后查看它实际上是System.Int32struct。没关系。现在您可以抓住 ILDasm 并查看它是什么System.Int32:转过身来,它是一个非常简单的结构,具有一个类型字段int32(这是int32CLR 内部的),并且没有用于加法的重载运算符。

那么,这是如何int с = a + b工作的呢?我再次抓住 ILDasm 并查看 IL。事实证明,System.Int32IL 代码中没有:编译器自动理解它应该将其替换为int32. 并且有 IL 指令add适用于int32堆栈上的几个。更让我开心的是,CLR 允许调用System.Int32on的实例方法int32。对我来说,这就像一些黑魔法。

所以,这里有一个纯粹的理论问题:似乎它System.Int32和其他类型一样,它可以在 C# 中以某种方式创建吗?如果可以的话,你能用它做任何有用的事情吗(实际int32字段是私有的)?

编辑:好的,为了更清楚一点:这个问题与int别名无关System.Int32。可以采用提供的示例,替换intSystem.Int32并跳过示例后的第一段。真正的问题是关于valuetype [mscorlib]System.Int32 a在您的 IL 代码中包含而不是仅包含int32 a.

4

3 回答 3

2

因此,请考虑以下代码:

    static void Main(string[] args)
    {
        int x = 5;
        Print(x);
        Console.ReadLine();
    }

    static void Print(object x)
    {
        int y = (int)x;
        Console.WriteLine(y);
    }

在 ILDasm 中:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  .maxstack  1
  .locals init ([0] int32 x)
  IL_0000:  nop
  IL_0001:  ldc.i4.5
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  box        [mscorlib]System.Int32
  IL_0009:  call       void Test.Program::Print(object)
  IL_000e:  nop
  IL_000f:  call       string [mscorlib]System.Console::ReadLine()
  IL_0014:  pop
  IL_0015:  ret
} // end of method Program::Main

.method private hidebysig static void  Print(object x) cil managed
{
  .maxstack  1
  .locals init ([0] int32 y)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  unbox.any  [mscorlib]System.Int32
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000e:  nop
  IL_000f:  ret
} // end of method Program::Print

[mscorlib]System.Int32仅用于装箱/拆箱。当变量在堆栈中时,它总是int32.


Int32 和 int

将 System.Int32 视为 int32 的影子类型可能会有所帮助。

以下 C# 代码:

int x = 0;
x.ToString();

这是在 IL 中:

ldc.i4.0
stloc.0
ldloca.s 0
call instance class System.String [mscorlib]System.Int32::ToString()
pop

请注意它是如何将 int32 传递给看似不兼容的 System.Int32 结构的。引擎允许这样做,因为它已经硬连线将 System.Int32 识别为 int32 的影子类型。

于 2012-10-26T08:45:52.303 回答
1

int32int(== System.Int32)

了解 .NET 原始类型

int32 是 CLR 原语。然后在 FCL 中,它由 System.Int32 结构体表示。System.Int32 的整数值被持久化在它的 m_value 字段中,并且在 System.Int32 上定义了很多与整数相关的方法。

在 C# 中,int 只是 System.Int32 的别名,由 C# 编译器支持。所以 int 和 System.Int32 之间没有依赖关系

来自IL“CLR 的语言”

无论使用什么语言开发应用程序,.NET 下的所有编译器都会生成中间语言。事实上,CLR 不会知道用于开发应用程序的语言。所有语言编译器都会生成一种统一的通用语言,称为中间语言。

因此,在 C#System.Int32中,我们拥有 IL int32。我不知道直接从 C# 代码中使用 IL 的方法,实际上也没有任何理由。

有一个:在 C#/VB.Net 中允许内联 IL 的工具


至于intvs System.Int32

关于 SO:C#、int 或 Int32 的 int 和 System.Int32 的帖子?我应该关心吗?

在 MSDN 中:

  1. Int32 结构
  2. int(C# 参考)

全部都是一样:

Int32 i = new Int32();
Int32 j = 5;
int x1 = 2;
Int32 x2 = x1;

int可以说是语法糖...实际上是 System.Int32

除了看看 C# 语言规范 4.1.4 简单类型:

C# 提供了一组预定义的结构类型,称为简单类型。简单类型通过保留字标识,但这些保留字只是 System 命名空间中预定义结构类型的别名,如表中所述

在哪里

  1. 短 => System.Int16
  2. int => System.Int32
  3. 长 => System.Int64

等等。

于 2012-10-26T07:07:38.710 回答
0

CLR 有一组原始类型,它们由 CorElementType 枚举定义。 http://msdn.microsoft.com/en-us/library/ms232600.aspx

add、sub、div、rem 等操作码对这些类型进行操作。JIT 会将这些转换成一些快速的汇编代码。你不能定义新的。如果您有兴趣,可以查看它使用 SOS 生成的代码。

如果您想模拟语言体验,您可以在您的类型中使用运算符重载。 http://msdn.microsoft.com/en-us/library/8edha89s.aspx

于 2012-10-26T06:58:26.797 回答