今天在学C++的时候就突然想到C#能不能实现类似于C++的Cin和Cout的输入输出模式,于是就动手写了一下,发现想完全实现一样的功能是比较困难的,不过类似的功能还是可以的,以下是我的实现思路。
cout
操作符重载
众所周知,C++的Cin和Cout的基本使用方式如下。
int a, b;
std::cin >> a >> b;
std::cout << a + b << std::endl;
其中<<以及>>是流式运算符,基本原理是利用了C++的操作符重载。因此,C#应该也可以通过操作符重载来实现这个功能。
cout实现
首先我们来实现比较简单的Cout输出。
class OStream
{
public static readonly OStream Cout = new();
public static string Endl => Environment.NewLine;
public static OStream operator <<(OStream stream, object obj)
{
Console.Write(obj);
return stream;
}
}
使用方法如下,基本和C++一样。
_ = Cout << "Hello, World!" << endl; // Hello, World!
不过可能有细心的同学会发现,前面多了一个_ =,面对一个不知道的问题,首先我们先问这是什么?然后再问为什么?
弃元
所以这是什么呢,首先这是一个赋值操作,等号左边为需要赋值的内容,右边是表达式,不过需要注意的是下划线 _ 并不是一个变量,而是C#的弃元,他的作用就是表示这个表达式的值我不需要,don't care。知道了这个作用之后,就可以解释这一行代码的作用了,这一行的作用就是输出“Hello World”,然后将这个表达式的值丢弃。
然后就是为什么需要这么做呢?显得非常莫名其妙,这其实应该算是C#的一个语法问题,C#的表达式不能单独作为一个语句,所以我们必须加上一个赋值操作,他才能独立存在。
cin
实现cout之后大家应该可以猜想到cin的实现方式了,就是借助操作符重载从输入流中读取数据之后再放入对应的对象中。
但是的话,这里就有一个问题,如何借助函数来对一个函数参数赋值,而函数参数通常只是一个副本,例如以下操作。
void Increase(int a)
{
a++;
}
相信大家都能看出来这个函数并不能实现+1的功能,那需要怎么做呢?我们可以看看C++里面是如何实现的。
void Increase(int &a)
{
a++;
}
两份代码非常相似,但是C++的代码多了一个&符号代表引用,而正是通过引用,实现了这个功能,那C#呢,很幸运,C#也拥有类似的功能——引用参数。
引用参数ref
该参数的用法简单来说就是C++的引用参数传递,是的参数传递时不是传递一个副本,而是传递本体。ref使用方法如下。
void Increase(ref int a)
{
a++;
}
int a = 1;
Increase(ref a);
Console.WriteLine(a); // 2
大家需要注意的时候,在使用C#的引用参数时,我们需要显示的指出引用参数,也就是在参数前加上ref关键字。按理来说,我们有了以上的功能应该就可以实现cin的功能了,但是很不幸的是,C#的操作符重载不支持ref参数。所以我们还需要其他的办法。
既然引用无法使用,那么我们会想到C++的另一种输入方式,或者说是C的一种输入方式——scanf。
int a;
scanf("%d", &a);
而scanf则是使用了指针来实现这个功能,可能使用过C#的同学就会说了,C#没有指针啊,那这个方法也使用不了了,正常来说确实是这样子没错,但是C#有一个关键字unsafe。
不安全代码unsafe
那么这个unsafe关键字有什么用呢?它的作用就是允许你在C#中使用不安全代码,那么什么是不安全代码呢?简单来说就是带有指针的代码,没错,C#同样也是支持指针的,不过官方并不推荐我们使用,所以可能很多同学并不知道C#的指针,同样的,如果我们想要使用指针的话需要使用unsafe关键字来开启指针。以下就是unsafe的用法。
unsafe
{
int a = 1;
int *p = &a;
*p = 2;
Console.WriteLine(a); // 2
}
可以看到C#中的指针和C++中指针用法基本一致。
cin实现
基于unsafe,我可以使用指针来实现上述操作。以下是具体实现。
class IStream
{
public static readonly IStream Cin = new();
public static unsafe IStream operator >>(IStream stream, int* obj)
{
*obj = Convert.ToInt32(Console.ReadLine());
return stream;
}
public static unsafe IStream operator >>(IStream stream, string* str)
{
*str = Console.ReadLine();
return stream;
}
//...
}
在使用的时候我们也需要加上unsafe,使用方法。
unsafe
{
int a = 0;
_ = Cin >> &a;
}
总结
以上就是C#实现C++中的cin以及cout的办法。这只是一个非常简陋的实现方式,当然,应该也没人会有实现这个功能的需要,所以大家当个乐看就好,不过我觉得其中涉及的一些C#语法,大家可以去了解一下,因为虽然我们不一定需要C#版本的cin和cout,但是我们会需要这些特殊的语法来帮助我们更好的编写代码。最后,如果大家有什么问题和建议,欢迎在评论区提出!