Main()方法是程序的入口点,C#程序中必须包含一个Main()方法,在该方法中可以创建对象和调用其他方法,但是C#所有的Main()方法都必须是静态的。
C#是一种完全面向对象的编程语言,即使是程序的启动入口,它也是一个类的成员。由于程序启动时还没有创建类的对象,因此,必须将入口点Main()方法定义为静态方法,使它可以不依赖于类的实例对象而执行。
目前我了解到程序被打包成.exe文件后,给外界唯一的接口就是main方法。使用者双击.exe文件,其实就是让虚拟机执行main方法。main方法不是提供给程序员的,而是提供给虚拟机和使用客户的(虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现),一个软件你没法让客户知道你内部的详情,当然客户也就没办法知道怎么去实例化对象,更不知道实例化对象时需要输入什么参数了,所以只能采用静态方法。
换个角度假设没有static关键字,那意味着需要生成一个实例后才可以调用这个Main方法,而Main方法是程序入口点,你没有进入Main方法,自然无法生成一个实例,既然没有实例,那就无法调用Main函数,岂不矛盾?所以Main函数被设置为static。直接通过类名加方法的形式调用Main()方法,使得我们不需要创建对象的实例(即new出该对象)而直接调用Main函数。
以下是代码展示方便理解:
namespace text1
{
class Program
{
public void instanceMember()
{
}
public static void staticMember()
{
}
static void Main(string[] args)
{
instanceMember();//报错,因为调用了实例成员,而却没有实例的对象
staticMember();//正确,直接调用静态成员
Program a1 = new Program();//实例化本类型的一个明确对象
a1.instanceMember();//正确,在这个对象上调用实例成员
a1.staticMember();//报错,不能在实例对象上调用静态成员
}
}
}
Main()函数的注意事项
1.Main()函数保护级别没有特殊要求, public,protected,private等都可,但是不应该为公共方法,若不加修饰符,编译器在编译时会默认设置为private。
2.Main()函数名的第一个字母要大写,否则将不具有入口点的语义。
3.参数可以作为从零开始索引的命令行参数来读取。
分析Main()方法的返回值和参数
Main()方法的参数默认是一个字符串(string[] args),此字符串数组用来运行时接受用户输入的参数(命令行参数);因为字符串在开发语言中是具有普遍性的,所以使用字符串是最优选择;数组的话,因为我们的参数不止一个,所以数组肯定是合适的.这里需要注意:
static void Main(string[]args){}表示无返回值,以字符串数组作为参数。
static void Main(){}表示无返回值,无参数。
static int Main(){return 0;}表示返回int类型数值,无参数。
static int Main(string[]args){return 0;}表示返回int类型数值,以字符串数组作为参数。
实际上返回值默认是void,我们可以进行修改,但完全没有必要。
C#语言默认会进行返回int,即使声明函数的时候使用的是void,也会隐式的返回一个int类型的值,当为0的时候,表示正常启动,不为0的时候,表示有错误发生。
Main方法可以重载吗?
通过前文我们可以得知,Main方法和其他普通方法还不太一样 ,普通方法是通过对象去调用的,即使写了一个普通的静态方法,我们也是通过类名去调用的,但是Main方法我们几乎从来没有主动的去调用过它,因为它由虚拟机直接调用。那么从概念上可以对Main方法进行重载吗?(重载的定义就是一个类中有两个以上的同名方法,但是使用的参数类型、个数或顺序不同,调用时编译器根据不同情况调用需要的方法)我尝试的结果是可以的,代码如下:
static void Main(string[] args)
{
Main("少年");
Console.ReadKey();
}
static void Main(string args)
{
Console.WriteLine("牛马" + args);
}
输出结果为:牛马少年
结论:Main方法可以被重载,但这只是从语法结构上和重载的定义上理解,倘若从底层虚拟机调用来说,我们上文有提到,Main方法与它所在的类没有任何关系,它只是被安排放在某个类中,你完全把它放在任意的其它类中,不影响任何使用效果。(因为它是由虚拟机专属的一个调用方法,跟我们这个类没关系)所以从这个角度出发的话,这两个方法压根就不是一个人去用的。即使下面这个方法长得很像是Main方法,但它其实就是普通类下的一个普通方法而已,只不过名字上比较特殊。
PS:正常情况下开发时几乎没有人会这样去写一个重载的Main方法,因为它太容易和虚拟机的Main方法混淆了。
Main方法能被其他方法调用吗?
既然Main方法它本身也是一个方法,那它可以被其他的方法调用吗?我之前也从来没有去试过,接下来我用代码简单实验一下:
static void Main(string[] args)
{
test("Main方法能被调用");
Console.ReadKey();
}
static void test(string args)
{
Main(new string[] { });
}
输出结果为:Process is terminated due to StackOverflowException.(栈溢出)
这个代码一执行一定会产生一个栈内存溢出的错误,相信大家学过递归或者方法底层原理的都知道,在方法执行的过程中,它每一次都会在栈内存当中开辟一个临时的空间去执行,所以如果你不把它当做一个Main方法而是把它当做普通方法的话,普通的方法他俩之间来回调用,语法上没问题,但如果执行就肯定不行。倘若一定要执行应该怎么办呢?我认为可以像递归一样给它设置一个出口:
static int num = 3;
static void Main(string[] args)
{
Console.WriteLine("Main方法被调用" + num);
if (num <= 0)
{
return;
}
test();
Console.ReadKey();
}
static void test()
{
num --;
Main(new string[] { });
}
输出结果为 :Main方法被调用3 Main方法被调用2 Main方法被调用1 Main方法被调用0
结论:通过上述代码我们可知即使是作为应用程序入口的 main 方法,也是可以被其他方法调用的,不过需要注意调用的手法。
Main方法可以继承吗?
假如我们在父类当中有一个Main方法,我需要写一个子类去继承父类,那既然是继承,父类下的公有的属性和方法都能被子类继承过去,那我们把Main方法的访问修饰符改为public,那么它能继承给子类吗?我们用代码测试一下:
public class Son:Program
{
public void test()
{
Main(new string[] { });
}
}
我们可以在上面代码的基础上测试,这段代码的语法是不报错的。也就意味着子类它调用的是自己继承过来的Main方法,因为它不用在调用方法前加上父类类名Program。
结论:Main方法是可继承的
Main是否可以存在多个,如何设置启动那个Main()函数?
在一个解决方案中,可能具有多个Main函数(在不同的项目中),设置启动项,可以告知编译器在编译的时候应用程序启动应该调用那个Main函数。(在菜单栏“项目——属性”中,能够指定启动对象)