gpt4 book ai didi

c# - C# 会从聚合结构/类中受益吗?

转载 作者:行者123 更新时间:2023-12-04 07:44:41 25 4
gpt4 key购买 nike

就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center为指导。




9年前关闭。




前言

tl;wr:这是一个讨论。

我知道这个“问题”更像是一个讨论,因此我将其标记为社区维基。然而,根据How to Ask页面,它可能属于这里,因为它与编程相关,经过一个小时的研究,在网络上的任何地方都没有讨论,具体的,与大多数 C# 程序员相关,并且是主题。此外,问题本身就是为了获得答案,对此我会保持开放的态度,无论我的偏见如何: C# 真的会从聚合结构中受益吗? 尽管有这个前言,我理解这将被关闭,但如果有权限和意图关闭的用户将我重定向到 Web 上的适当讨论点,我将不胜感激。

介绍

缺乏结构可变性

结构 在 C# 中是灵活但有争议的类型。它们提供堆栈分配的值类型组织范式,但不提供其他值类型的不变性。

有人说结构应该代表值,而值不会改变(例如 int i = 5; , 5 是不可变的),而有些人认为它们是带有子字段的 OOP 布局。

关于 struct immutability ( 1 , 2 , 3 ) 的争论也没有解决,目前的解决方案似乎是让程序员强制执行不变性。

例如,C# 编译器将在将结构作为引用访问时(this page 的底部)检测可能的数据丢失并限制赋值。此外,由于结构构造函数、属性和函数能够执行任何操作,限制(对于构造函数)在返回控件之前分配所有字段,结构 cannot be declared as constant ,如果它们仅限于数据表示,这将是一个正确的声明。

结构体、聚合体的不可变子集

聚合 类( Wikipedia )是功能有限的严格数据结构,注定要提供语法糖,因为它们缺乏灵活性。在 C++ 中,它们“没有用户声明的构造函数,没有私有(private)或 protected 非静态数据成员,没有基类,也没有虚函数”。尽管核心概念保持不变,但 C# 中此类类的理论细节在此仍有待讨论。

由于聚合结构是带有标记访问器的严格数据持有者,因此它们的不变性(在可能的 C# 上下文中)将得到保证。聚合也不能为空,除非指定了空运算符 ( ? ),就像其他纯值类型一样。出于这个原因,许多非法的结构操作以及一些语法糖将成为可能。

用途

  • 聚合可以声明为 const,因为它们的构造函数将被强制执行除了分配字段之外什么都不做。
  • 聚合可以用作方法参数的默认值。
  • 聚合可以是隐式顺序的,促进与本地的交互
  • 聚合将是不可变的,强制执行引用访问不会丢失数据。此类子字段修改的编译器检测可能会导致完整的、隐式的 reassignment.libraries。


  • 假设语法

    从 C++ 语法中,我们可以想象以下内容:
    (请记住,这是一个社区维基,欢迎并鼓励改进)
    aggregate Size
    {
    int Width;
    int Height;
    }

    aggregate Vector
    {
    // Default values for constructor.
    double X = 0, Y = 0, Z = 0;
    }

    aggregate Color
    {
    byte R, G, B, A = 255;
    }

    aggregate Bar
    {
    int X;
    Qux Qux;
    }

    aggregate Qux
    {
    int X, Y;
    }

    static class Foo
    {
    // Constant is possible.
    const Size Big = new Size(200, 100);

    // Inline constructor.
    const Vector Gravity = { 0, -9.8, 0 };

    // Default value / labeled parameter.
    const Color Fuschia = { 255, 0, 255 };
    const Vector Up = { y: 1 };

    // Sub-aggregate initialization
    const Bar Test = { 20, { 4, 3 } };

    static void SetVelocity(Vector velocity = { 0, 1, 0 }) { ... }
    static void SetGravity(Vector gravity = Foo.Gravity) { ... }

    static void Main()
    {
    Vector v = { 1, 2, 3 };

    double y = v.Y; // Valid.

    v.Y = 5; // Invalid, immutable.
    }
    }

    隐式(重新)分配

    截至今天,在 C# 4.0 中分配结构的子字段是有效的:
    Vector v = new Vector(1, 2, 3);
    v.Z = 5; // Legal in current C#.

    但是,有时,编译器可以检测何时错误地将结构体作为引用访问,并禁止更改子字段。例如,( example question )
    //(in a Windows.Forms context)
    control.Size.Width = 20; // Illegal in current C#.

    Size是属性(property)和 struct Size值类型,我们将编辑实际属性的副本/克隆,这在这种情况下是无用的。作为 C# 用户,我们倾向于假设大多数东西都是通过引用访问的,尤其是在 OOP 设计中,这会让我们认为这样的调用是合法的(如果 struct Sizeclass ,那就是合法的)。

    此外,在访问集合时,编译器还禁止我们修改结构子字段:( example question )
    List<Vector> vectors = ... // Imagine populated data.
    vectors[4].Y = 10; // Illegal in current C#.

    关于这些不幸的限制的好消息是,编译器为这种情况做了一半可能的聚合解决方案:检测它们何时发生。另一半是隐式地重新分配具有更改值的新聚合。
  • 在本地范围内时,只需重新分配向量。
  • 在外部作用域中时,找到一个 get,如果可以访问匹配的 set 访问器,则重新分配给这个访问器。

  • 为此,为了避免混淆,必须将委托(delegate)标记为隐式:
    implicit aggregate Vector { ... }
    implicit aggregate Size { ... }


    // Example 1
    {
    Vector v = new Vector(1, 2, 3);
    v.Z = 5; // Legal with implicit aggregates.

    // What is implicitly done:
    v = new Vector(v.X, v.Y, 5); // Local variable, simply reassign.
    }

    // Example 2
    {
    //(in a Windows.Forms context)
    control.Size.Width = 20; // Legal with implicit aggregates.

    // What is implicitly done:
    Size old = control.Size.__get(); // External, MSIL detects a get.
    // If MSIL can find a matching, accessible __set:
    control.Size.__set({ 20, old.Height });
    }

    // Example 3
    {
    List<Vector> vectors = ... // Imagine populated data.
    vectors[4].Y = 10; // Legal with implicit aggregates.

    // What is implicitly done:
    Vector old = vectors[4].__get(); // External, MSIL detects a get.
    // If MSIL can find a matching, accessible __set:
    vectors[4].__set({ old.X, 10, old.Z });
    }

    // Example 4
    {
    Vector The5thVector(List<Vector> vectors) { return vectors[4]; }
    ...
    List<Vector> vectors = ...;
    The5thVector(vectors).Y = 10; // Illegal with implicit aggregates.

    // This is illegal because the compiler cannot find an implicit
    // "set" to match. as it is a function return, not a property or
    // indexer.
    }

    当然,这最后的隐式重新分配只是一种句法简化,可以或不可以采用。我只是提出它,因为编译器似乎能够检测到这种对结构的引用访问,并且如果它是一个聚合,则可以轻松地为程序员转换代码。

    概括
  • 聚合可以有字段;
  • 聚合是值类型;
  • 聚合是不可变的;
  • 聚合分配在堆栈上;
  • 聚合不能继承;
  • 聚合具有顺序布局;
  • 聚合有一个顺序的默认构造函数;
  • 聚合不能有用户定义的构造函数;
  • 聚合可以有默认值和标记结构;
  • 聚合可以内联定义;
  • 聚合可以声明为常量;
  • 聚合可以用作默认参数;
  • 除非指定( ? ),否则聚合是不可为空的;

  • 可能:
  • 聚合(可以)被隐式重新分配;请参阅 Marcelo Cantos 的回复和评论。
  • 聚合(可以)有接口(interface);
  • 聚合(可以)有方法;


  • 缺点

    由于聚合不会取代结构,而是另一种组织方案,我找不到很多缺点,但希望 S/O 的 C# 老手能够填充这个 CW 部分。最后一点,请直接回答问题并进行讨论:C# 是否会像这篇文章中描述的那样从聚合类中受益?我在任何方面都不是 C# 专家,而只是 C# 语言的爱好者,并且错过了这个对我来说似乎至关重要的功能。我正在向有经验的程序员寻求有关此案例的建议和评论。 我知道存在许多变通方法,并且每天都在积极使用它们 ,我只是认为它们太常见而不能被忽略。

    最佳答案

    我希望首先使用类似于您提出的语义来定义结构。

    然而,我们被困在我们现在拥有的东西上,我认为我们不太可能在 CLR 中获得一种全新的“类型”。引入一种新类型意味着将它引入每种 .NET 语言,而不仅仅是 C#,这是一个很大的变化。

    我认为更有可能的是——记住,当我谈论假设的、未宣布的 future 产品的假设语言功能时,这些产品不存在并且可能永远不会存在,我这样做只是为了娱乐目的——是我们会找到一些方法来对类和结构进行更好的不变性注释和实现。无论所讨论的类型是值类型还是引用类型,编译器都可以在强制不变性和更容易以不可变风格进行编程方面做得更好。如果编译器或 CLR 具有更多的在编译时或 jit 时已知的不变性保证,那么编译器或 CLR 也有可能更好地优化在多核机器上运行的代码。

    当你对你的提议犹豫不决时,你可能想要考虑的一个有趣的问题是:如果聚合类型有方法,“this”是一个值还是一个变量?例如:

    aggregate Vector
    {
    int x, y, z;
    public void M(Action action)
    {
    Console.WriteLine(this.x);
    action();
    Console.WriteLine(this.x);
    }
    }
    ...
    Vector v = new Vector(1, 2, 3);
    Action action = ()=>{ v = new Vector(4, 5, 6); };
    v.M(action);

    发生什么了? “this”是按值传递给 M 的,在这种情况下,它会写出两次“1”,还是作为对变量的引用传递,在这种情况下,您所谓的“不可变”类型会发生变异? (因为变异的是变量;根据定义,变量是允许变异的,这就是为什么它们被称为“可变的”。)

    关于c# - C# 会从聚合结构/类中受益吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4721132/

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