【问题标题】:Is there a shorthand for "passthrough" properties in C#?C# 中是否有“直通”属性的简写?
【发布时间】:2020-01-13 00:39:40
【问题描述】:

我正在我的应用中实现“保存/加载”功能。有各种类型的Vertex 对象有很多静态字段,但是apparently 你不能序列化静态字段。我正在创建一个其实例包含这些字段的类,并且为了避免填充这些字段的代码过多,我将它们作为属性来实现。

但是,这样做的语法似乎过于庞大,所以我正在寻找一种方法来简化它:

public Color CircleFillColor { get => CircleVertex.fillColor; set => CircleVertex.fillColor = value; }
public Color SquareFillColor { get => SquareVertex.fillColor; set => SquareVertex.fillColor = value; }
public Color TriangleFillColor { get => TriangleVertex.fillColor; set => TriangleVertex.fillColor = value; }

如果我们在 C# 中有 macros,我可以这样写:

#define passthru(F) { get => F; set => F = value; }
public Color CircleFillColor passthru(CircleVertex.fillColor)
public Color SquareFillColor passthru(SquareVertex.fillColor)
public Color TriangleFillColor passthru(TriangleVertex.fillColor)

有这样的属性的简写吗?

【问题讨论】:

  • 什么是Vertex 对象?为什么不能将它们更改为实例成员并像往常一样序列化Vertex 实例?
  • T4 模板可以做你想做的事。 partial class 将包含使用静态字段反射生成的属性。
  • 您可以改为通过反射进行序列化,这个答案有一个示例说明您可能希望如何做到这一点stackoverflow.com/a/5261678/10431
  • @Sinatr A Vertex 有一个 X/Y 坐标、一个 PictureBox、一个在 PictureBox 上绘制其形状的方法以及一些用于拖放的逻辑。每个CircleVertex 必须有一个FillColor,每个SquareVertex 和每个TriangleVertex 也应该有一个,所以static 字段似乎是一个自然的选择。根据我的喜好,数据和演示文稿有点太接近了,但这正是规范所要求的。
  • 取决于您的喜好。您将如何对静态类的更改做出反应,任何生成的代码或手动编写的代码都是静态的 - 不会自动更新。反射本身就是一些编程,如果您想要这种自动性,或者您有超过 20 或 50 个属性,则值得努力。写 20 行愚蠢的行,你犯的错误比写 20 行聪明的行要少——但它们看起来并不优雅。你想让你的代码看起来不错吗?真的是偏好问题。

标签: c# syntax properties


【解决方案1】:

没有直接等效于宏的方法。另一种方法是封装调用,以牺牲两个额外的方法为代价,产生最少更短的属性,并将受影响的fillColor 属性移动到每个方法中,而不是在每个属性中重复两次。

public Color CircleFillColor { get => GetColor(CircleVertex); set => SetColor(CircleVertex, value); }
public Color SquareFillColor { get => GetColor(SquareVertex); set => SetColor(SquareVertex, value); }
public Color TriangleFillColor { get => GetColor(TriangleVertex); set => SetColor(TriangleVertex, value); }

private Vertex GetColor(Vertex vertex)
{
  return vertex.fillColor;
}

private void SetColor(Vertex vertex, Color color)
{
  vertex.fillColor = color;
}

【讨论】:

  • 我的一个想法是相似的,但正如所写的那样,它不起作用,因为CircleVertex 和朋友是类型,而不是实例,而GetColorSetColor 期待Vertex 实例.这段代码在非静态字段上工作得很好,但我看不出这在静态字段上是如何工作的。
  • @Danya02 我不明白“CircleVertex 和朋友是类型,而不是实例”。如何将属性值分配给类型?你的意思是它们是静态的还是抽象的?我理解原始问题的方式,例如CircleVertex 是一个静态字段,具有静态属性 fillColor
  • 我不确定你的意思。 WhateverVertex 是一个类型,所以你可以做Vertex v = new WhateverVertex(),它有一个fillColor 静态字段。因为不能将静态字段/属性声明为抽象类的一部分(其中Vertex 是其中之一),所以实际上没有静态保证如果您定义class MyVeryOwnVertex : Vertex,那么MyVeryOwnVertex.fillColor 将是有效的。因为对此没有静态保证,但实际上每个Vertex 子类都会有一个fillColor,AFAIK 我不能使用任何好的OOP 特性来做到这一点。
【解决方案2】:

我最终使用了 Visual Studio 中包含的 T4 text templates。因为我的目标是减少我需要手工编写的代码量,这样在例如复制/粘贴代码。

在我的项目中有CircleVertexSquareVertexTriangleVertex的类型,每个类型都有一个单独的fillColorstrokeColor。这可以被认为是一个嵌套循环,T4 允许这样写。

例如,这是我最终使用的代码。相关语法部分是<# ... #>中的东西是C#代码,遇到此行时<#= foo #>被替换为foo的值。

<#
String[] shapes = new String[] {"Circle","Square","Triangle"};
String[] colors = new String[] {"fillColor", "strokeColor"};
foreach(var shape in shapes){
    foreach(var color in colors){
#>
[XmlElement(Type = typeof(XmlColor))]
public Color <#=shape#>_<#=color#>
{
    get => <#=shape#>Vertex.<#=color#>;
    set => <#=color#>Vertex.<#=shape#> = value; 
}
<#}#>

这扩展为:

[XmlElement(Type = typeof(XmlColor))]
public Color Circle_fillColor
{
    get => CircleVertex.fillColor;
    set => CircleVertex.fillColor = value;
}
[XmlElement(Type = typeof(XmlColor))]
public Color Circle_strokeColor
{
    get => CircleVertex.strokeColor;
    set => CircleVertex.strokeColor = value;
}
[XmlElement(Type = typeof(XmlColor))]
public Color Square_fillColor
{
    get => SquareVertex.fillColor;
    set => SquareVertex.fillColor = value;
}

...snip...

[XmlElement(Type = typeof(XmlColor))]
public Color Triangle_strokeColor
{
    get => TriangleVertex.strokeColor;
    set => TriangleVertex.strokeColor = value;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-23
    • 2020-12-11
    • 2021-10-31
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 2016-06-25
    • 2016-08-10
    相关资源
    最近更新 更多