C# --- 设置常量 constant, readonly

C# --- Constructor, Object Initializer, Property, Constant, and Readonly

  • Constructor and Object Initializer
  • Fields and Property
  • 如何设置常量

Constructor and Object Initializer

  • constructor用来初始化, 可以被overload, 通过input parameter识别调用哪个constructor
  • 如果没有自定义的constructor, 编译器会自动生成一个无参constructor
  • 如果有自定义的constructor, 则不会自动生成无参constructor. 如果需要无参constructor,需要显示的写出来
  • constructor的权限一般都是public, 但是也可以用private修饰. 这样可以控制实例的生成. (如单例模式用static方法返回唯一的实例)
  • 使用this关键字可以在一个constructor调用另外一个constructor
public class Wine
{
	 public decimal Price;
	 public int Year;
	 public Wine (decimal price) { Price = price; }
	 public Wine (decimal price, int year) : this (price) { Year = year; }
	 public Wine (decimal price, DateTime year) : this (price, year.Year) { }
}

Object Initializer

  • Object Initializer提供了另外一种初始化Object的方法
public class Bunny
{
	 public string Name;
	 public bool LikesCarrots;
	 public bool LikesHumans;
	 public Bunny () {}
	 public Bunny (string n) { Name = n; }
}

// Note parameterless constructors can omit empty parentheses
Bunny b1 = new Bunny { Name="Bo", LikesCarrots=true, LikesHumans=false };
Bunny b2 = new Bunny ("Bo") { LikesCarrots=true, LikesHumans=false };

//The code to construct b1 and b2 is precisely equivalent to the following:
//The temporary variables are to ensure that if an exception is thrown during initiali‐
//zation, you can’t end up with a half-initialized object.
Bunny temp1 = new Bunny(); // temp1 is a compiler-generated name
temp1.Name = "Bo";
temp1.LikesCarrots = true;
temp1.LikesHumans = false;
Bunny b1 = temp1;

Bunny temp2 = new Bunny ("Bo");
temp2.LikesCarrots = true;
temp2.LikesHumans = false;
Bunny b2 = temp2;

为什么使用 Object Initializer 而不使用构造函数

  • 通常来讲使用构造函数更好,这样可以防止构建的object存在invalid state的情况 (如在多线程的情况下)
  • 但是有一些成员变量的初始化不是必要的, 而是optional的. 这是就需要将构造函数overload来满足不同的初始化需求. 而大量的构造函数重载降低了代码可读性并且增加了代码的复杂度. 这时候就可以使用Object Initializer.
  • 可以用在创建Anonymous object: var v = new { Amount = 108, Message = "Hello" }; 并且用在LINQ中, 如下
var productInfos =
    from p in products
    select new { p.ProductName, p.UnitPrice };
MyObject myObjectInstance = new MyObject(param1, param2)
{
    MyProperty = someUsefulValue
};

//This will behave about the same as if you do this:

MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;

Fields and Property

Fields

  • 一个类或者struct的成员变量被称为 field
  • 一个filed可以被readonly关键字修饰, readonly可以保证在变量在被创建完成后不会被修改.
  • readonly变量只能在声明或者构造函数里被赋值
  • 注意如果用readonly修饰一个collection, readonly只能保证collection的reference不会被修改, 但是collection里面的内容还是可以被修改的, 推荐使用Immutable library
  • filed可以不用被初始化, 未被初始化的field有default value (0, ‘\0’, null, false)
  • field的初始化在构造函数之前执行

Property

  • Property 提供对一个private fields的读写操作. (也就是集成了setter 和 getter)
  • 一个Property包括set 和 get
  • get会返回对应private field的值
  • set可以对传入的数值进行一些validation或者转换, 然后将值赋给对应的private field

Example:

  • In this example, the TimePeriod class represents an interval of time.
  • Internally, the class stores the time interval in seconds in a private field named _seconds. and a read-write property named Hours allows the customer to specify the time interval in hours.
  • Both the get and the set accessors perform the necessary conversion between hours and seconds.
  • In addition, the set accessor validates the data and throws an ArgumentOutOfRangeException if the number of hours is invalid.
public class TimePeriod
{
    private double _seconds;

    public double Hours
    {
        get { return _seconds / 3600; }
        set
        {
            if (value < 0 || value > 24)
                throw new ArgumentOutOfRangeException(nameof(value),
                      "The valid range is between 0 and 24.");

            _seconds = value * 3600;
        }
    }
}

TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;

// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
// The example displays the following output:
//    Time in hours: 24

Auto-implemented properties

如何设置常量

constant

  • 用constant修饰的变量, 编译器会在编译时静态的求值. 也就是直接将变量替换成值. constant可以是bool, char, string, 任何内置的数值类型或者枚举类型
public static double Circumference (double radius)
{
 return 2 * System.Math.PI * radius;
}

//会被编译成

public static double Circumference (double radius)
{
 return 6.2831853071795862 * radius;
}

static readonly

  • static readonly也可以用来设置常量, 但是不同的是, static readonly变量不会在编译的时候被替换, 所以遇到每次运行都需要新的值的情况,需要用static readonly修饰
static readonly DateTime StartupTime = DateTime.Now;
  • 另外一个区别是,public const decimal ProgramVersion = 2.3; 如果assembly Y引用了assembly X的常量. 当Y编译时, 会储存常量2.3. 但是如果X重新编译将值改为2.4. 则Y不会更新这个值,直到Y重新编译. 而static readonly会避免这个错误
  • 其实就是const只有在重新编译的时候才会更新,但是static readonly会在运行时更新

你可能感兴趣的:(#,C#,---,语法糖,c#)