0

这是结构的良好候选者吗?

考虑这个不可变结构示例,其中构造函数验证输入并将验证数据存储为单个“路由代码”:

struct RoutingCode
{
  private readonly string routingCode;

  RoutingCode(string prefix, string service, string sender)
  {
    // Validate prefix, service, sender strings
    // ...

    if (isInvalid) throw ArgumentException();

    // 
    this.routingCode = prefix + service + sender;
  }

  // Gets the validated routing code.
  public string Routing
  {
    return this.routingCode;
  }

  public int RoutingLength
  {
    return this.routingCode.Length;
  }
}

在我看来,这个简化的示例是使用 astruct而不是a 的好选择class

  • 它是不可变的。
  • 它代表一个奇异值。
  • 实例大小很小。

问题是所有结构都有一个隐式的默认构造函数。在这个例子中,默认构造函数RoutingCode()将实例化一个Routing属性返回的对象null——这是一个无效的路由代码。Point这与其他结构不同,例如BigInteger支持字段包含默认实例的非常合乎逻辑且有效的“零”。

除了不确保有效的路由代码之外,该RoutingLength属性还会在默认实例上引发NullReferenceExceptionif 调用。

保持 this astruct与使其成为 a的论据是class什么?

4

2 回答 2

2

您可以轻松解决默认值问题:

struct RoutingCode
{
  private readonly string routingCode;    
  RoutingCode(string prefix, string service, string sender)
  {
    // Validate prefix, service, sender strings
    // ...
    if (isInvalid) throw ArgumentException();
    this.routingCode = prefix + service + sender;
  }

  public string IsValid 
  {
    get { return this.routingCode != null; }
  }

  // Gets the validated routing code.
  public string Routing
  {
    get { return this.routingCode; }
  }

  public int RoutingLength
  {
    get { return this.routingCode == null ? 0 : this.routingCode.Length; }
  }
}

好的,现在所有属性都不会引发异常,并且您可以判断该值是否无效。手头的问题是这是否是结构的良好候选者。你是对的,它(1)不可变,(2)小,(3)逻辑上是一个值。如果您愿意接受可以表示无效值的事实,那么这可能是结构的良好候选者。

不过,一个更好的问题是:这是否有充分的理由不成为一堂课?与其寻找反对使其成为结构的反对意见,不如寻找反对使其成为类的反对意见。

于 2013-03-18T04:23:26.607 回答
0

隐藏字段结构可能具有未初始化实例的行为,就好像它们拥有任何特定的所需值[对于给定类型的所有未初始化实例,默认值必须相同]。只需让每个属性访问器或方法检查该类型是否包含系统默认值,如果是,则替换所需的默认值。

如果希望允许代码创建一个实例,Routingnull没有这样的实例假设这Routing是默认值,则可以让该类型声明一个等于新 GUID 的静态字符串(或其他不会出现的东西其他地方),然后修改构造函数和get方法:

static string stringRepresentingNull = Guid.NewGuid().ToString();

RoutingCode(string wholeString)
{
  if (wholeString == null) 
    wholeString = stringRepresentingNull;
  this.routingCode = wholeString;
}

public string Routing
{
  get { 
    if (this.routingCode == null) 
      return "12-3456-789"; // Default routing string
    else if (Object.ReferenceEquals(routingCode,stringRepresentingNull)
      return null;
    else
      return routingCode;
}

请注意,即使外部代码以某种方式设法猜测与类型关联的 GUID,外部代码也无法生成字符串 where ReferenceEqualswill match stringRepresentingNull

同样,如果想要拥有int一个默认值为 123 的属性,则可以存储backingField=(desiredValue ^ 123)并拥有属性 getter yield backingField ^ 123

类型应该是结构还是类的问题很大程度上归结为一个人是否希望类型的默认值表现为 anull或作为有效值。如果想要一个空默认值,请使用一个类。如果想要一个有效的默认值,请使用结构。

于 2013-12-20T23:01:01.217 回答