【C#小知识】C#中一些易混淆概念总结(四)---------解析Console.WriteLine()

目录:

【C#小知识】C#中一些易混淆概念总结

【C#小知识】C#中一些易混淆概念总结(二)

【C#小知识】C#中一些易混淆概念总结(三)

----------------------------------分割线--------------------------------------

 

这几天在温习结构体和类的时候遇到一个问题。发现一个奇怪的现象,一直找不到合理的答案。但是今天终于找到了合理的答案,所以拿来和大家分享一下。

我们首先来看下面的一段代码:

复制代码
class Program
    {
        static void Main(string[] args)
        {

            Point p;
            Console.WriteLine(p);

           
            Point p1 = new Point();
            Console.WriteLine(p1);
            Console.ReadKey();

        }
    }
    //定义结构
    struct Point
    {
        ////定义时赋初始值,编译器会报错
        //private int x;

        //public Point()
        //{ }
    }

    class Person
    {
        //在类中我们可以为属性赋初始值
        //private int nAge = 5;

        //public int NAge
        //{
        //    get { return nAge; }
        //    set { nAge = value; }
        //}

    }
复制代码

 

当我们只是声明一个类和一个结构体的时候,我们的编译器顺利的编译通过。并且打印出结果如下:

 

为什么我们没有在结构和类中做任何操作,却可以打印出结果,且是“命名空间+"."+数据类型”呢?

 

首先我查阅了MSDN的关于结构(struct)的官方文档(地址点击这里),有如下的一段话:

 

结构默认的构造函数(如果没有显式声明)在实例化的时候才会被调用。所以,   

复制代码
        //结构的实例化可以不使用NEW关键字,只是将p加载到栈空间中,但是对象不可用,这里没有调用默认的构造函数
            Point p2;
            Console.WriteLine(p2);

            Console.WriteLine(p2);
            Console.ReadKey();
复制代码

在内存中是如下的情况:

 

此时在栈中已经存在了p这个对象,但是不可用。

 

那么为什么会打印出“命名空间+"."+数据类型”的结果呢?

我们先看一下VS编译后的中间代码,即Msil,详细解释在图中给出:

 

有中间语言代码,我们可以知道,最后调用的是Console.WriteLine(Object)方法

 

这时候就要深入的研究一下Console类了,用反编译工具.NET Reflector查看Console类,因为在上面的代码中,传进.WriteLine()方法的是一个类,所以,我们要查看它的的(object value)方法,如下图:

 

这时候,我们再深入到WriteLine()方法中去,源代码,如下:

 

再看Out.WriteLine()的源代码:

因为p已经在栈中创建了对象(但是不可用),所以,直接进入else语句。

 

明显的可以发现IFormattable是一个接口,我们再看IFormattable接口的源码,如下:

 

显然我们的Point 结构没有实现一个ToString()方法,不存在继承关系,所以会转化失败,返回一个null值,又进入下一个else语句

else
        {
            this.WriteLine(value.ToString());
        }

这时候最重要的就要来了,我们看到value值被转换为字符串输出了,在看ToString()源代码,如下:

 

很明显的发现,是获取该对象的数据类型并且转化为字符串输出。如下代码:

复制代码
        Point p;
            //打印出p的数据类型
            Console.WriteLine(p.GetType());

            Point p2;
            Console.WriteLine(p2);

           //使用NEW实例化了对像,调用了默认的构造函数
            Point p1 = new Point();
            Console.WriteLine(p1);
            Console.ReadKey();
复制代码

 

打印结果:

 

 

这样对结构和类的了解有没有更深入的了解呢?




毕业实习交流群:221376964。你也可以关注我的新浪微博进行交流。

<think>好的,我现在需要回答用户的问题:“C#-> 运算符吗?”首先,我得确认用户提到的“->”运算符在C#中是否存在,以及它的用途是什么。 首先,我回忆一下C#的运算符列表。C#中的运算符包括算术运算符、比较运算符、逻辑运算符等等。常见的如+、-、*、/、==、&&、||等等。而“->”这个符号在其他语言中,比如C和C++中,通常用于指针访问成员的运算符,例如结构体指针访问成员时使用p->member。但C#在设计上尽量减少指针的使用,提倡使用引用类型和垃圾回收机制,只有在不安全的代码块中才允许使用指针。 所以,接下来我需要确认在C#的不安全代码上下文中是否允许使用“->”运算符。根据记忆,C#确实支持在不安全代码中使用指针,并且在这种情况下,可以使用“->”来通过指针访问结构体的成员。例如,定义一个结构体,创建指针,然后使用->来访问成员。 不过,用户可能并不熟悉不安全代码概念,所以需要解释清楚,说明在普通情况下不会用到这个运算符,只有在明确使用unsafe关键字和启用允许不安全代码编译选项的情况下才能使用。同时,提醒用户大多数情况下不需要使用指针,C#的托管环境已经处理好了内存管理。 另外,可能存在的混淆点是C#中的Lambda表达式使用“=>”运算符,比如在匿名函数或表达式体中,例如x => x * x。需要区分“->”和“=>”,避免用户混淆。 为了确保准确性,最好给出一个简单的代码示例,展示如何在unsafe环境下使用“->”运算符,并说明必要的步骤,比如编译时需要启用不安全代码。同时,对比C/C++中的用法,说明C#中的限制和适用场景。 最后,总结一下,确认C#中存在“->”运算符,但仅限于不安全代码中,并且大多数应用开发中不需要使用,避免误导用户认为这是常见操作。</think>C# 中确实存在 `->` 运算符,但它的使用场景非常特殊,**仅限于不安全代码(unsafe code)**中操作指针时使用。以下是详细说明: --- ### 1. **基本用途** `->` 用于通过**指针**访问结构体(struct)的成员,类似于 C/C++ 中的指针成员访问。 **示例:** ```csharp unsafe { Point point = new Point { X = 10, Y = 20 }; Point* p = &point; // 获取指针 int x = p->X; // 通过 -> 访问成员 Console.WriteLine(x); // 输出 10 } // 结构体定义 struct Point { public int X; public int Y; } ``` --- ### 2. **使用条件** - **必须启用不安全代码**:在项目属性中勾选 `Allow unsafe code`(或在编译时加`/unsafe`参数)。 - **必须用 `unsafe` 块包裹**:所有指针操作必须在 `unsafe { ... }` 内。 --- ### 3. **对比其他语法** - **普通对象成员访问**:用 `.`(例如 `obj.Property`)。 - **Lambda 表达式**:C# 用 `=>`(例如 `x => x * x`),与 `->` 无关。 - **C/C++ 的 `->`**:功能类似,但 C# 严格限制在 `unsafe` 上下文中。 --- ### 4. **实际应用场景** - **低级内存操作**:如高性能数值计算、硬件交互。 - **调用原生代码**:与 C/C++ 库交互时可能需要指针操作。 - **绝大多数场景不需要**:C# 的托管内存机制已足够安全高效。 --- ### 总结 `->` 在 C# 中是一个**低级、受限的运算符**,仅在明确启用不安全代码时用于指针操作。日常开发中建议优先使用 C# 的安全特性(如引用类型、GC 等)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值