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

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

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

Expression body definitions

  • 使用expression定义setter和getter
public class SaleItem
{
    string _name;
    decimal _cost;

    public SaleItem(string name, decimal cost)
    {
        _name = name;
        _cost = cost;
    }

    public string Name
    {
        get => _name;
        set => _name = value; //value不是自定义的 代表输入的值
    }

    public decimal Price
    {
        get => _cost;
        set => _cost = value;
    }
}
public class SettingValue : DatabaseDocument
{
	public Id Identifier { get: init; }
	public scope scope { get; init; }
	
	[BsonIgnore]
	public JsonElement JsonValue
	{
		get => BsonValue .ToJsonElement(); //通过BsonValue拿到
		init => BsonValue = value .ToBsonValue(); //设置BasonValue
	}
	
	[BsonELement("Value")] 
	public BsonValue BsonValue f get; init: }
}

Auto-implemented properties

//编译器可以自动生成对应的field
 
public class SaleItem
{
    public string Name
    { get; set; }

    public decimal Price
    { get; set; }
}

Property initializers

  • 可以用 property initializer 对 auto properties 进行初始化
public decimal CurrentPrice { get; set; } = 123;
//初始化List
public class ConfiqurationModel 
{
	public string Code { get; init; }
	public IReadOnlylist<SectionDefinitionModel> Sections  { get; init; } = Array.Empty<SectionDefinitionmiodel>()
	public IReadonlylist<SettingDefinitionModel> Settings { get; init; } = Array.Empty<SettingDefinitionMlodel>():
}

readonly property

  • public int Maximum { get; } = 999; 没有set 表示这是readonly property
  • public Id Identifier { get: init; } init表示只能在初始化的时候赋值, 其他情况只能读取
  • 下面代码是通过构造函数初始化值, 初始化之后就只能读取数据
public SettingDefinitionModelWithcontext(SettingDefinitionodel setting, string namespace, string sectionCode) : base(setting)
{
	Namespace = @namespace;
	SectionCode = sectionCode:
}
public string Namespace { get; }
public string SectionCode { get;}

如何设置常量

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会在运行时更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值