• C# 对象和类型(2) 持续更新


    class PhoneClass 
    {
        public const string DayOfSendingBill = "Monday";
        public int CustomerID;
        public string FirstName;
        public string LastName;
    }

    结构

    struct PhoneStruct
    {
        public const string DayOfSendingBill = "Monday";
        public int CustomerID;
        public string FirstName;
        public string LastName;
    }

    类是存储在堆(heap)上的引用类型,而结构是存储在栈(stack)上的值。较小的数据类型是使用结构,可提供性能。

    类和结构,都需要使用 new 来声明实例。

    PhoneClass phone = new PhoneClass()
    PhoneStruct phone = new PhoneStruct()

    类函数成员

    • 方法是与某个类相关的函数,与数据成员一样,函数成员默认为实例成员,实用static修饰符可以把方法定义为静态方法。
    • 属性是可以从客户端访问的函数组,其访问方式与访问类的公共字段类似。
    • 构造函数是实例化对象时自动调用的特殊函数。它必须与类同名,且不能有返回类型。
    • 终结器(析构函数) 名称与类名相同 前面有个 "~" 符号。
    • C#允许已有的运算符应用于自己的类,进行运算符重载。
    • 索引器允许对象以数组或集合的方式进行索引。

    函数传递参数

    对于复杂的数据类型,按引用传递效率更高,因为按值传递时,必须复制大量数据。

    ref 参数

    迫使值参数通过引用传送给方法,方法对变量所做的改变,都会影响原始对象值。

    static void Main(string[] args)
    {
        int i = 20;
        Console.WriteLine("{0}",i);
        Modify(ref i);
        Console.WriteLine("{0}", i);
        Console.ReadLine();
    }
    
    static void Modify(ref int i)
    {
        i = 100;
    }

    C# 要求传递方法的参数必须进行初始化。

    out参数

    out关键字初始化,传递给该方法的变量可以不初始化,方法返回时,方法内对变量所做的改变,都会保留下来。

    static void Main(string[] args)
    {
        int i;
        Modify(out i);
        Console.WriteLine("{0}", i);
        Console.ReadLine();
    }
    
    static void Modify(out int i)
    {
        i = 100;
    }

    命名参数

    允许是通过参数名,按任意顺序传递。

    static void Main(string[] args)
    {
        Console.WriteLine("{0}", FullName("John", "Doe"));
        Console.WriteLine("{0}", FullName(lastName: "Doe", firstName: "John"));
        Console.ReadLine();
    }
    
    static string FullName(string firstName, string lastName)
    {
        return firstName + " " + lastName;
    }

    可选参数

    可选参数必须提供默认值,且必须是在定义在方法的最后的参数。

    static void Main(string[] args)
    {
        Console.WriteLine("{0}", FullName(firstName: "John"));
        Console.ReadLine();
    }
    
    static string FullName(string firstName, string lastName="Default")
    {
        return firstName + " " + lastName;
    }

    方法重载

    方法名相同,参数的个数 或 类型不同。

    class TestFun
    {
        void DoFun(string result)
        {
            
        }
    
        void DoFun(int result)
        {
    
        }
    }

    方法重载不能使用可选参数,可通过函数重载来实现此目的。

     public void DoFun(string result)
     {
         this.DoFun(result, 0);
     }
    
     public void DoFun(string result,int index)
     {
         Console.WriteLine("DoFun2");
     }
    • 两个方法不能仅在返回类型上有区别。
    • 两个方法不能仅根据参数是声明为ref还是out来区分。

    属性

    private string _someProperty;
    public string SomeProperty
    {
        get { return _someProperty; }
        set { _someProperty = value; }
    }

    自动实现属性

     public string SomeProperty { get; set; }

    属性访问修饰符

    C#允许给属性的 get 和 set 访问器设置不同的访问修饰符。在 get 和 set 访问器中,必须有一个具备属性的访问级别。

    public string SomeProperty { get; private set; }

    通过属性访问字段,需要担心带来性能损失。C#代码会编译为IL,然后在运行时JIT编译为本地可执行代码。JIT编译器可以生成高度优化的代码,并在适当的时候随意地内联代码。任何内联代码完全有ClR决定,不能像C++中像 inline 这样关键字控制方法是否内联。

    构造函数

    构造函数声明一个与类同名的方法,且没有返回类型。

    class TestFun
    {
        private int _number;
        public TestFun(int number)
        {
            this._number = number;
        }
    }
    
    TestFun testFun = new TestFun(12);

    私有化构造函数

    class TestFun
    {
        private int _number;
        private TestFun(int number)
        {
            this._number = number;
        }
    }
    • 类仅用某些静态成员或属性的容器,因此永远不会实例化它。
    • 类仅通过调用某个静态成员函数来实例化

    静态构造函数

    static TestFun()
    {
        
    }

    静态构造函数,是在加载类时,有 .net 运行库调用它,静态构造函数不能带参数,一个类也只能有一个静态构造函数。静态构造函数只能访问静态成员,不能访问类的实例成员。

    无参数的实例构造参数与静态构造参数可以同一类中同时定义。

    class TestFun
    {
        public static readonly string BackColor;
    
        static TestFun()
        {
            DateTime now = DateTime.Now;
            switch (now.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    BackColor = "Green";
                    break;
                default:
                    BackColor = "Red";
                    break;
            }
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("{0}",TestFun.BackColor);
            Console.ReadLine();
        }
    }

    从构造函数中调用其他构造函数

    class Car
    {
        public string description;
        public uint numWheels;
    
        public Car(string description, uint numWheels)
        {
            this.description = description;
            this.numWheels = numWheels;
        }
    
        public Car(string description): this(description, 4)
        {
    
        }
    
        //public Car(string description)
        //{
        //    this.description = description;
        //    this.numWheels = 4;
        //}
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Car car = new Car("Audio");
            Console.WriteLine("{0}    {1}",car.description,car.numWheels);
            Console.ReadLine();
        }
    }

    这是C# 特殊语法,称为构造函数初始化器。注意 初始化器不能有多个调用。

     public Car(string description): this(description, 4)

    只读字段

    只读字段只能在构造函数中给只读字段赋值,只读字段可以是一个实例字段。如果要把只读字段设置为静态,必须显示声明它。

    public static readonly uint StaticCars;
    static Car()
    {
        StaticCars = 12;
    }
    
    public readonly uint SampleCars;
    
    public Car()
    {
        SampleCars = 13;
    }

    静态只读,只能在静态构造函数赋值。实例只读,在实例构造函数赋值。当然也可以在声明时赋值。

    匿名类型

    var 和 new 一起使用创建匿名类型。

    var caption = new {FirstName = "James", LastName = "Leonard"};

    结构

    结构是值类型,定义结构和类完全相同。

    struct Car
    {
        public int nWheel;
        public string description;
    
        public Car(string description,int nWheel)
        {
            this.description = description;
            this.nWheel = nWheel;
        }
    }
    • 结构不支持继承。
    • 对于结构,构造函数是不允许替换的。
    • 使用结构,可以指定字段如何在内存中布局。
    Car car = new Car("Audio",4);
    Console.WriteLine("{0}    {1}",car.description,car.numWheels);
    
    Car car2 = new Car();
    car2.description = "BMW";
    car2.numWheels = 4;
    Console.WriteLine("{0}    {1}", car2.description, car2.numWheels);

    结构分配内存时,速度非常快,因为它们将内联或者保存在栈中。在结构超出了作用作用域,删除也是很快。负面影响,当把结构作为参数传递时,结构的所有内容就被复制,对于类就不会。应使用 ref 参数传递,以避免性能损失。

    结构的构造函数

    构造函数的方式与类定义构造函数方式相同,但不允许定义无参数的构造函数。

    结构不能在绕过构造函数进行赋值,否则会出现编译错误。

    也可以像类一样 提供 Close 或 Dispose 方法。

    弱引用

    只要有代码引用它,就会形成强引用。弱引用创建和使用对象,它在垃圾回收器回收时,就会回收对象并释放内存。

    弱引用由 WeakReference 创建 

    MathTest math = new MathTest();
    WeakReference mathReference = new WeakReference(math);
    if (mathReference.IsAlive)
    {
        math = mathReference.Target as MathTest;
        math.x = 1000;
        math.y = 500;
        Console.WriteLine("{0}", math.Value);
    }

    部分类

    partial 关键字允许把类、结构、方法或接口放在多个文件中。

    用法放在 class、struct、interface前面。

    // MathTest1.cs
    partial class MathTest1
    {
        public void MethodOne()
        {
            
        }
    }
    
    // MathTest2.cs
    partial class MathTest1
    {
        public void MethodTwo()
        {
            
        }
    }

    这样这个类 MathTest1 就拥有了 两个方法。

    静态类

    在 class 前面加上 static,就声明了静态类。静态类里不能拥有实例成员和函数。

     static class Math
     {
         public static int Add(int x, int y)
         {
             return x + y;
         }
     }
    
     class Program
     {
         static void Main(string[] args)
         {
             Math.Add(10, 20);
             Console.ReadLine();
         }
     }

    Object类

    如果定义类时没有指定基类,编译器就会自动假定这个类派生自 Object。

    结构总是派生自 System.ValueType。 System.ValueType 又派生自 System.Object

    System.Object 方法

    • ToString()                         获取对象表示的字符串。如果需要复杂的字符串表示,需要实现 IFormattable 接口。
    • GetHashCode()                  如果对象放在名为映射的数据结构中,就是使用这个方法。使用该方法确定放在什么地方。
    • Equals 和 ReferenceEquals   比较对象相等性
    • Finalize                              类似析构函数,在垃圾回收时,重写Finalize函数,系统会自动调用它,执行。Object 实现的函数,实际什么也没有做。
    • GetType            返回总 System.Type  派生类的一个实例。
    • MemberwiseClone               等到一个浅复制的对象。该方法不是须方法,所以不能重写它。

    ToString实例

    class Money
    {
        public decimal amount;
    
        public override string ToString()
        {
            return "$" + amount.ToString();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Money money = new Money();
            money.amount = 1000;
            Console.WriteLine("{0}",money);
    
            decimal amount = 200;
            Console.WriteLine("{0}", amount);
    
            Console.ReadLine();
        }
    }

    扩展方法

    假设想在Money中添加一个方法 AddToAmount。但是由于某种原因不能在源文件中修改。此时可以扩展方法。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplicationCShape
    {
        public class Money
        {
            public decimal amount;
    
            public override string ToString()
            {
                return "$" + amount.ToString();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Money money = new Money();
                money.amount = 1000;
                money.AddToAmount(200);
                Console.WriteLine("{0}",money);
    
                Console.ReadLine();
            }
        }
    }
    
    namespace ConsoleApplicationCShape
    {
        public static class MoneyExtension
        {
            public static void AddToAmount(this Money money, decimal amountToAdd)
            {
                money.amount += amountToAdd;
            }
        }
    }

    如果扩展方法与类方法同名,就不会调用扩展方法。

  • 相关阅读:
    SVG
    JavaScript的性能优化
    sublime长期使用的快捷键
    spring实现AOP
    java之spring
    JAVA面试题02
    java面试题01
    MyBatis之关联关系
    MyBatis之动态sql
    MyBatis之sql映射文件
  • 原文地址:https://www.cnblogs.com/z888/p/5770758.html
Copyright © 2020-2023  润新知