C#方法的总结详解

 更新时间:2020年6月25日 11:41  点击:3524
C#方法
1:实例构造器和类
2:实例构造器和结构
3:类型构造器
4:操作符重载方法
5:转换操作符方法
6:扩展方法
7:部分方法
1:实例构造器和类
构造器是允许将类型的实例初始化为良好状态的一种特殊方法,创建一个引用类型的实例时,先为实例的数据字段分配内存,然后初始化对象的附加字段(类型对象指针和同步索引),最后调用构造函数来设置对象的初始状态。构造函数不能被继承,所以不能被virtual、new、override、sealed和abstract修饰,若没有显示定义任何构造函数,编译器将定义一个无参的public构造函数,但若是抽象类,编译器将定义一个无参的protected的构造函数
创建一个类的实例并不一定非要调用构造函数。
1:使用Object的MemberwiseClone()方法。他的作用就是创建当前 System.Object 的浅表副本,内部工作机制是分配内存,初始化对象的附加字段(类型对象指针和同步索引),然后将源对象的字节数据复制到新对象中。从下面的代码可以看出MemberwiseClone()实现了对象复制,而不是简单的对象引用。
复制代码 代码如下:

class Program
    {
        public int X;
        static void Main(string[] args)
        {
            Program p = new Program();
            p.X = 1;
            Program q = (Program)p.MemberwiseClone();
            Program z = p;
            p.X = 2;
            Console.WriteLine("p.X=" + p.X);//输出:p.X=2
            Console.WriteLine("q.X=" + q.X);//输出:q.X=1
            Console.WriteLine("z.X=" + z.X);//输出:z.X=2
            Console.Read();
        }
    }

2:反序列化。在网络编程的时候,经常将一个对象序列化成二进制,然后传输出去,接收端反序列化成原来的对象,反序列化使用的是类
System.Runtime.Serialization.FormatterServices的方法public static object GetUninitializedObject(Type type)或
public static object GetSafeUninitializedObject(Type type)分配内存,而在这两个方法内部没有调用要被反序列化对象的构造函数。
字段的初始化代码会被编译器自动添加到相应的构造函数中,非静态字段的初始化代码会自动加到实例构造函数中,静态字段的初始化代码则添加到静态构造函数中,如果你的代码中有多个字段被初始化,还有多个构造函数的话,初始化代码在每个构造函数中都会有一份,这无疑会让你的生成文件(如DLL,EXE文件)变大。
证明这一点的代码如下:
复制代码 代码如下:

public class SomeType
    {
        public  int x=1,y=2,z=3;
        public SomeType() { }
        public SomeType(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public SomeType(int x)
        {
            this.x = x;
        }
}
//经过IL反编译,方法SomeType(int x, int y)代码如下
.method public hidebysig specialname rtspecialname
        instance void  .ctor(int32 x,
                             int32 y) cil managed
{
  // 代码大小       45 (0x2d)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  stfld      int32 MyTest.SomeType::x
  IL_0007:  ldarg.0
  IL_0008:  ldc.i4.2
  IL_0009:  stfld      int32 MyTest.SomeType::y
  IL_000e:  ldarg.0
  IL_000f:  ldc.i4.3
  IL_0010:  stfld      int32 MyTest.SomeType::z
  IL_0015:  ldarg.0
  IL_0016:  call       instance void [mscorlib]System.Object::.ctor()
  IL_001b:  nop
  IL_001c:  nop
  IL_001d:  ldarg.0
  IL_001e:  ldarg.1
  IL_001f:  stfld      int32 MyTest.SomeType::x
  IL_0024:  ldarg.0
  IL_0025:  ldarg.2
  IL_0026:  stfld      int32 MyTest.SomeType::y
  IL_002b:  nop
  IL_002c:  ret
} // end of method SomeType::.ctor

先执行了初始化代码,其他构造函数都包含了初始化代码,然后在执行构造函数中的赋值代码,要解决这个代码膨胀问题,方法很简单,把初始化代码写在无参构造函数中,让其他构造函数调用。
2:实例构造器和结构
值类型的工作方式与引用类型截然不同,值类型其实并不需要定义构造函数,地球人根本阻止不了值类型实例化,编译器根本不会生产默认无参构造函数,如果你显示声明无参构造函数,编译根本通过不了,报错“结构不能包含显式的无参数构造函数”。由于值类型存在栈中,根本不需要对堆中的数据进行引用,所以我们可以在定义的时候就直接赋值,(int i=0;string s=”a”;Point p;p.X=2;)他根本不需要new,new当然是可以的,调用构造函数会初始化所有的字段成相应类型的默认值,实例如下:
复制代码 代码如下:

public struct Point
    {
        public int x, y;
        //public Point() { }//错:结构不能包含显式的无参数构造函数
        //public int z = 4;//错:结构中不能有实例字段初始值设定项
        //public Point(int x) //在控制返回调用方之前,字段“Point.y”必须被完全赋值,要解决这个问题就手动给y加一个默认值吧,
        //你也可以加this=new Point();将所有的字段的值初始化为0或null
        //{
        //    this.x = x;
        //}
        public void Test()
        {
            Point p;
            p.x = 1;
            p.y = 2;
            Console.WriteLine(p.x+","+p.y);//输出1,2
        }
    }

结构的特点:
   1:不能显示定义无参构造函数
   2:不能在定义字段的时候初始化
   3:声明有参构造函数的时候,要初始化所有的字段
3:类型构造器
实例构造器就是静态构造函数,他的作用是设置类型的初始化状态,静态构造函数只能有一个,且是无参的,不能有访问修饰符修饰,默认就是private,由编译器调用执行。实例如下:
复制代码 代码如下:

public class SomeType
    {
        public static int x = 520;
        static SomeType()
        {
            x = 112;
        }
    }

    //用.NET reflector查看源码,如下
    public class SomeType
    {
        public static int x ;
        static SomeType()
        {
            x = 520;
            x = 0x70;
        }
        public SomeType() { }
    }

在定义静态字段并初始化,编译器会自动生成一个类型构造器(静态构造函数),并将静态字段的初始化代码插在类型构造器的前面,从上面的代码可以看出,定义时初始化和在类型构造器中初始化只需要一个即可,还有112的16进制为0x70,所以在代码中看到16进制也不用大惊小怪,根本不涉及性能问题,若定义了静态字段,但没有初始化任何一个,编译器是不会生成类型构造器的。但是静态字段还是会被初始化,其实不管是静态的还是非静态的字段都是会被编译器自动初始化的,int类型的初始化为0;bool:False;string:null,这就是为什么你在实例化实体的时候,有些字段你没有初始化,却不会报错,而且你知道没有初始化的字符串的值就是null,也就是说编译器会帮你初始化你没有初始化的字段,然而在方法中定义的局部变量是需要自己初始化的,如果你没有初始化,会报一个错误“使用了未赋值的局部变量X”。
4:操作符重载方法
要想实现操作符重载,只需要保证以下两点,其他的话都是浮云:
1:操作符重载方法必须是public和static方法
2:操作符重载方法至少有一个参数的类型与当前定义这个方法的类型相同。之所以是要这个条件是为了使编译器在合理的时间内找到要绑定的操作方法
,实例如下
复制代码 代码如下:

public class Complex
    {
        public int data;
        public Complex(int data)
        {
            this.data = data;
        }
        public static Complex operator +(Complex c1, Complex c2)
        {
            return new Complex(c1.data+c2.data);
        }
        public void Test()
        {
            Complex c1 = new Complex(1);
            Complex c2 = new Complex(2);
            Complex c3 = c1 + c2;
            Console.WriteLine(c3.data);//输出3
        }
    }

5:转换操作符方法
要实现转换操作符方法,条件和操作符重载方法的条件是一样的,实例如下:
复制代码 代码如下:

public class Rational
    {
        public Rational(int data)
        {
            this.data = data;
        }
        public Rational(char data)
        {
            this.data = (int)data;
        }
        //隐式类型转换:int->Rational
        public static implicit operator Rational(int data)
        {
            return new Rational(data);
        }
        //隐式类型转换:char->Rational
        public static implicit operator Rational(char data)
        {
            return new Rational(data);
        }
        //显示类型转换 Rational->int
        public static explicit operator int(Rational val)
        {
            return val.data;
        }
        //显示类型转换 Rational->char
        public static explicit operator char(Rational val)
        {
            return Convert.ToChar(val.data);
        }
        public void Test()
        {
            Rational r1 = 1;//将int类型隐式转换成Rational
            Rational r2 = '2';//将char类型隐式转换成Rational
            int i = (int)r1;//将Rational类型显示转换成int
            char c = (char)r2;//将Rational类型显示转换成char
            Console.WriteLine("i=" + i);//输出:i=1
            Console.WriteLine("c=" + c);//输出:c=2
        }

        int data;
    }

隐式和显示类型转换的实现原理就这么简单,在C++中隐式类型转换根本不需要你写代码,只要有相应的public构造函数就可以了,如int转换成Rational,只需要有构造函数public Rational(int data)就可以了,如Rational r=1;编译器会尽一切努力寻找将int类型转换成Rational的方法,当它发现这个构造函数,他说都不说就帮你进行转换了,就因为这样有时候非常坑爹,你一个int类型无缘无故的就变成Rational了,而你却根本不知道怎么回事,有时候为了解决这个问题,还得自己定义一个类(Uint)来封装int,然后构造函数改成Rational(Uint data),C#就没有这个问题,当然你要想实现隐式类型转换就自己写代码吧。
6:扩展方法
实现扩展方法的条件:
1:定义扩展方法的类必须是非泛型静态类
2:这个类必须有自己的作用域,即不能是内部类
3:方法必须是public和static
4:方法的第一个参数必须用this修饰,第一个参数就是你要扩展的类型,实例如下:
复制代码 代码如下:

public static class StringExtensions
    {
        public static int ToInt(this string s)
        {
            return Convert.ToInt32(s);
        }
        public void Test()
        {
            string s = "2";
            Console.WriteLine(s.ToInt());
        }
}

7:部分方法
你懂的
[!--infotagslink--]

相关文章

  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • php 中file_get_contents超时问题的解决方法

    file_get_contents超时我知道最多的原因就是你机器访问远程机器过慢,导致php脚本超时了,但也有其它很多原因,下面我来总结file_get_contents超时问题的解决方法总结。...2016-11-25
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • HTTP 408错误是什么 HTTP 408错误解决方法

    相信很多站长都遇到过这样一个问题,访问页面时出现408错误,下面一聚教程网将为大家介绍408错误出现的原因以及408错误的解决办法。 HTTP 408错误出现原因: HTT...2017-01-22
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • php抓取网站图片并保存的实现方法

    php如何实现抓取网页图片,相较于手动的粘贴复制,使用小程序要方便快捷多了,喜欢编程的人总会喜欢制作一些简单有用的小软件,最近就参考了网上一个php抓取图片代码,封装了一个php远程抓取图片的类,测试了一下,效果还不错分享...2015-10-30
  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02