gpt4 book ai didi

c# - 这个不可变结构应该是一个可变类吗?

转载 作者:太空狗 更新时间:2023-10-29 17:28:30 24 4
gpt4 key购买 nike

我向一位程序员同事展示了这个结构,他们认为它应该是一个可变类。他们觉得没有空引用和根据需要更改对象的能力是不方便的。我真的很想知道是否还有其他原因使它成为一个可变类。

[Serializable]
public struct PhoneNumber : IEquatable<PhoneNumber>
{
private const int AreaCodeShift = 54;
private const int CentralOfficeCodeShift = 44;
private const int SubscriberNumberShift = 30;
private const int CentralOfficeCodeMask = 0x000003FF;
private const int SubscriberNumberMask = 0x00003FFF;
private const int ExtensionMask = 0x3FFFFFFF;


private readonly ulong value;


public int AreaCode
{
get { return UnmaskAreaCode(value); }
}

public int CentralOfficeCode
{
get { return UnmaskCentralOfficeCode(value); }
}

public int SubscriberNumber
{
get { return UnmaskSubscriberNumber(value); }
}

public int Extension
{
get { return UnmaskExtension(value); }
}


public PhoneNumber(ulong value)
: this(UnmaskAreaCode(value), UnmaskCentralOfficeCode(value), UnmaskSubscriberNumber(value), UnmaskExtension(value), true)
{

}

public PhoneNumber(int areaCode, int centralOfficeCode, int subscriberNumber)
: this(areaCode, centralOfficeCode, subscriberNumber, 0, true)
{

}

public PhoneNumber(int areaCode, int centralOfficeCode, int subscriberNumber, int extension)
: this(areaCode, centralOfficeCode, subscriberNumber, extension, true)
{

}

private PhoneNumber(int areaCode, int centralOfficeCode, int subscriberNumber, int extension, bool throwException)
{
value = 0;

if (areaCode < 200 || areaCode > 989)
{
if (!throwException) return;
throw new ArgumentOutOfRangeException("areaCode", areaCode, @"The area code portion must fall between 200 and 989.");
}
else if (centralOfficeCode < 200 || centralOfficeCode > 999)
{
if (!throwException) return;
throw new ArgumentOutOfRangeException("centralOfficeCode", centralOfficeCode, @"The central office code portion must fall between 200 and 999.");
}
else if (subscriberNumber < 0 || subscriberNumber > 9999)
{
if (!throwException) return;
throw new ArgumentOutOfRangeException("subscriberNumber", subscriberNumber, @"The subscriber number portion must fall between 0 and 9999.");
}
else if (extension < 0 || extension > 1073741824)
{
if (!throwException) return;
throw new ArgumentOutOfRangeException("extension", extension, @"The extension portion must fall between 0 and 1073741824.");
}
else if (areaCode.ToString()[1] == '9')
{
if (!throwException) return;
throw new ArgumentOutOfRangeException("areaCode", areaCode, @"The second digit of the area code cannot be greater than 8.");
}
else
{
value |= ((ulong)(uint)areaCode << AreaCodeShift);
value |= ((ulong)(uint)centralOfficeCode << CentralOfficeCodeShift);
value |= ((ulong)(uint)subscriberNumber << SubscriberNumberShift);
value |= ((ulong)(uint)extension);
}
}


public override bool Equals(object obj)
{
return obj != null && obj.GetType() == typeof(PhoneNumber) && Equals((PhoneNumber)obj);
}

public bool Equals(PhoneNumber other)
{
return this.value == other.value;
}

public override int GetHashCode()
{
return value.GetHashCode();
}

public override string ToString()
{
return ToString(PhoneNumberFormat.Separated);
}

public string ToString(PhoneNumberFormat format)
{
switch (format)
{
case PhoneNumberFormat.Plain:
return string.Format(@"{0:D3}{1:D3}{2:D4}{3:#}", AreaCode, CentralOfficeCode, SubscriberNumber, Extension).Trim();
case PhoneNumberFormat.Separated:
return string.Format(@"{0:D3}-{1:D3}-{2:D4} {3:#}", AreaCode, CentralOfficeCode, SubscriberNumber, Extension).Trim();
default:
throw new ArgumentOutOfRangeException("format");
}
}

public ulong ToUInt64()
{
return value;
}


public static PhoneNumber Parse(string value)
{
var result = default(PhoneNumber);
if (!TryParse(value, out result))
{
throw new FormatException(string.Format(@"The string ""{0}"" could not be parsed as a phone number.", value));
}
return result;
}

public static bool TryParse(string value, out PhoneNumber result)
{
result = default(PhoneNumber);

if (string.IsNullOrEmpty(value))
{
return false;
}

var index = 0;
var numericPieces = new char[value.Length];

foreach (var c in value)
{
if (char.IsNumber(c))
{
numericPieces[index++] = c;
}
}

if (index < 9)
{
return false;
}

var numericString = new string(numericPieces);
var areaCode = int.Parse(numericString.Substring(0, 3));
var centralOfficeCode = int.Parse(numericString.Substring(3, 3));
var subscriberNumber = int.Parse(numericString.Substring(6, 4));
var extension = 0;

if (numericString.Length > 10)
{
extension = int.Parse(numericString.Substring(10));
}

result = new PhoneNumber(
areaCode,
centralOfficeCode,
subscriberNumber,
extension,
false
);

return result.value != 0;
}

public static bool operator ==(PhoneNumber left, PhoneNumber right)
{
return left.Equals(right);
}

public static bool operator !=(PhoneNumber left, PhoneNumber right)
{
return !left.Equals(right);
}

private static int UnmaskAreaCode(ulong value)
{
return (int)(value >> AreaCodeShift);
}

private static int UnmaskCentralOfficeCode(ulong value)
{
return (int)((value >> CentralOfficeCodeShift) & CentralOfficeCodeMask);
}

private static int UnmaskSubscriberNumber(ulong value)
{
return (int)((value >> SubscriberNumberShift) & SubscriberNumberMask);
}

private static int UnmaskExtension(ulong value)
{
return (int)(value & ExtensionMask);
}
}

public enum PhoneNumberFormat
{
Plain,
Separated
}

最佳答案

处理电话号码的程序是进程的模型。

因此,让流程中不可变的东西在代码中不可变。使流程中可变的东西在代码中可变。

例如,一个流程可能包括一个人。一个人有一个名字。一个人可以更改他们的名字,同时保留他们的身份。因此,人对象的名字应该是可变的。

一个人有一个电话号码。一个人可以更改他们的电话号码,同时保留他们的身份。因此,一个人的电话号码应该是可变的。

电话号码有区号。电话号码不能更改其区号并保留其身份;你改变区号,你现在有一个不同的电话号码。因此,电话号码的区号应该是不可变的。

关于c# - 这个不可变结构应该是一个可变类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2465766/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com