【发布时间】:2021-06-11 03:09:17
【问题描述】:
TL:DR;创建一个结构,其中值在get 的开头为结构本身初始化自身(没有公共属性,但任何比较/等执行初始化),如果是这样,为什么?
我想知道以有效不可变的方式生成结构的有效默认值是多么糟糕的想法。我已经读过拥有一个可变结构等有多糟糕,但是如果你有一个没有公共属性的结构——它本身就是它所代表的值——并且该值对应于一些外部不可变资源,该怎么办?
例如,考虑以下结构:
using System;
public struct Computer
{
private string _name;
private string _domain;
private bool _isInitialized;
public static Computer Parse(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException("name");
}
var result = new Computer();
result._name = string.Copy(name);
result._domain = string.Empty;
result._isInitialized = true;
return result;
}
public static Computer Parse(string name, string domain)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException("name");
}
var result = new Computer();
result._name = string.Copy(name);
if (_domain == null) { result._domain = string.Empty; }
else { result._domain = string.Copy(domain); }
result._isInitialized = true;
return result;
}
private void Initialize()
{
if (!_isInitialized)
{
var source = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
_name = source.HostName;
_domain = source.DomainName;
_isInitialized = true;
}
}
public override string ToString()
{
Initialize();
if (!string.IsNullOrEmpty(_domain)) {
return _name + "." + _domain;
}
else {
return _name;
}
}
public override bool Equals(object other)
{
Initialize();
if (other is Computer)
{
var otherComputer = (Computer)other;
return _name.Equals(otherComputer._name, StringComparison.OrdinalIgnoreCase) &&
_domain.Equals(otherComputer._domain, StringComparison.OrdinalIgnoreCase);
}
else
{
return false;
}
}
// additional comparison methods omitted.
}
正如所见,Computer 实体的任何比较等操作都将导致初始化 - 实际上,观察 Computer 将导致它不再是 0 字节值。
我为什么要这么做?我想要类似于不可变值类型的东西,默认情况下,它代表 actual 值 - 而不是真正的默认结构,即 0 字节。然后我可以使用这样的东西作为参数的默认值:public void DoSomething(Computer computer = default) 并且知道default 表示本地设备 - 如果这不是ValueType,我将不得不传入null 作为默认值对于参数,因为不可能有一个常量引用类型(即不能有public void DoSomething(string computerName = Environment.MachineName))。
这意味着永远不会真正观察到 true “默认值” - 并且该结构永远不会被读取为 0 字节值,我读过的是值类型的 default本质上是。
为什么不应该我这样做 - 还是完全没问题?众所周知的代码中是否有应用这种做法的实例?
【问题讨论】:
-
我认为你所做的只是the singleton pattern。这是很常见的。在后来的几年里,它不再那么流行了。
-
我可以问你为什么首先使用结构吗?
_value是一个字符串 = System.String 是一个引用类型。您的代码中有更多奇怪的怪癖,例如初始化程序的“默认 null”参数(这可能是 hack?)。 -
@jhbonarius 也许 ComputerName 会是一个更好的例子。我可以编写一百个在“计算机”上运行的方法,并且需要一个
ComputerName参数,我希望它不仅仅是一个字符串。通过提供default(而不是“.”、“localhost”等),可以表明该方法应该针对本地设备——但您也可以使用ComputerName.Parse(string)来引用另一台计算机。这增加了对默认值行为的澄清和简化。 Local 单例可能会产生误导;这只是一个缓存的默认值,很像CancellationToken.None。 -
好吧,为什么不是一个只有只读字符串参数的简单类呢?或者 a record:
record Computer(string Name);var myComputer = new Computer("MyName");。你为什么想要一个单例(单个静态实例)? -
针对后一个问题,很多结构都包含引用类型成员。该结构代表一个服务标签,因此是它自己的不同实体,但数据存储为字符串。如果这是不好的做法,我想了解原因——我仍然有很多不明白的地方。 Null CimSession 将使用本地会话 - 在执行计算机上运行。我想我给这个参数一个默认值只是为了更快的测试。
标签: c# struct value-type