[c#] متى تستخدم البنية؟


Answers

كلما كنت لا تحتاج إلى تعدد الأشكال ، تريد الدلالات القيمة ، وتريد تجنب تخصيص الكومة وما يرتبط بها من جمع القمامة العامة. ومع ذلك ، فإن التحذير هو أن البنى (كبيرة بشكل تعسفي) أكثر تكلفة من تمرير المراجع الطبقية (عادة ما تكون كلمة آلة واحدة) ، بحيث يمكن أن تصبح الفصول أسرع في الممارسة.

Question

متى يجب أن تستخدم البنية وليس الطبقة في C #؟ نموذجي المفاهيمي هو أن البُنى تُستخدم في الأوقات التي يكون فيها العنصر مجرد مجموعة من أنواع القيم . طريقة لاحتجازهم منطقياً جميعاً في كتلة متماسكة.

جئت عبر هذه القواعد here :

  • يجب أن تمثل البنية قيمة واحدة.
  • يجب أن يكون للبنية بصمة ذاكرة أقل من 16 بايت.
  • لا يجب تغيير البنية بعد الإنشاء.

هل تعمل هذه القواعد؟ ماذا يعني بنية لغويا؟




استخدم بنية عندما تريد دلالات قيمة بدلاً من دلالات مرجعية.

تصحيح

لست متأكدا لماذا الناس يسقطون هذا ولكن هذا هو نقطة صحيحة ، وقدم قبل توضيح OP سؤاله ، وهذا هو السبب الأساسي الأكثر الأساسية للبنية.

إذا كنت بحاجة إلى دلالات مرجعية ، فأنت تحتاج إلى فصل وليس بنية.




A struct is a value type. If you assign a struct to a new variable, the new variable will contain a copy of the original.

public struct IntStruct {
    public int Value {get; set;}
}

Excecution of the following results in 5 instances of the struct stored in memory:

var struct1 = new IntStruct() { Value = 0 }; // original
var struct2 = struct1;  // A copy is made
var struct3 = struct2;  // A copy is made
var struct4 = struct3;  // A copy is made
var struct5 = struct4;  // A copy is made

// NOTE: A "copy" will occur when you pass a struct into a method parameter.
// To avoid the "copy", use the ref keyword.

// Although structs are designed to use less system resources
// than classes.  If used incorrectly, they could use significantly more.

A class is a reference type. When you assign a class to a new variable, the variable contains a reference to the original class object.

public class IntClass {
    public int Value {get; set;}
}

Excecution of the following results in only one instance of the class object in memory.

var class1 = new IntClass() { Value = 0 };
var class2 = class1;  // A reference is made to class1
var class3 = class2;  // A reference is made to class1
var class4 = class3;  // A reference is made to class1
var class5 = class4;  // A reference is made to class1  

Struct s may increase the likelihood of a code mistake. If a value object is treated like a mutable reference object, a developer may be surprised when changes made are unexpectedly lost.

var struct1 = new IntStruct() { Value = 0 };
var struct2 = struct1;
struct2.Value = 1;
// At this point, a developer may be surprised when 
// struct1.Value is 0 and not 1



I rarely use a struct for things. لكن هذا أنا فقط It depends whether I need the object to be nullable or not.

As stated in other answers, I use classes for real-world objects. I also have the mindset of structs are used for storing small amounts of data.




Structures are in most ways like classes/objects. Structure can contain functions, members and can be inherited. But structures are in C# used just for data holding . Structures does take less RAM than classes and are easier for garbage collector to collect . But when you use functions in your structure, then compiler actually takes that structure very similarly as class/object, so if you want something with functions, then use class/object .




باستثناء أنواع القيم التي يتم استخدامها بشكل مباشر من خلال وقت التشغيل والعديد من الأغراض الأخرى لأغراض PInvoke ، يجب عليك استخدام أنواع القيم فقط في سيناريوهين.

  1. عندما تحتاج إلى نسخ الدلالات.
  2. عندما تحتاج إلى التهيئة التلقائية ، عادةً في صفائف من هذه الأنواع.



تحتاج إلى استخدام "struct" في الحالات حيث تريد تحديد تخطيط الذاكرة بشكل صريح باستخدام StructLayoutAttribute - عادة لـ PInvoke.

تحرير: يشير التعليق إلى أنه يمكنك استخدام الفئة أو البنية مع StructLayoutAttribute وهذا صحيح بالتأكيد. في الممارسة العملية ، عادةً ما تستخدم بنية - يتم تخصيصها على المكدس مقابل كومة الذاكرة المؤقتة التي تكون منطقية إذا كنت فقط تمرير وسيطة إلى استدعاء أسلوب غير مُدار.




I think a good first approximation is "never".

I think a good second approximation is "never".

If you are desperate for perf, consider them, but then always measure.




هنا قاعدة أساسية.

  • إذا كانت جميع حقول الأعضاء هي أنواع قيم ، قم بإنشاء بنية .

  • إذا كان أي حقل عضو واحد هو نوع مرجع ، فقم بإنشاء فصل دراسي . هذا لأن حقل نوع المرجع سيحتاج إلى تخصيص الكومة على أي حال.

Exmaples

public struct MyPoint 
{
    public int X; // Value Type
    public int Y; // Value Type
}

public class MyPointWithName 
{
    public int X; // Value Type
    public int Y; // Value Type
    public string Name; // Reference Type
}



Briefly, use struct if :

1- your object properties/fields do not need to be changed. I mean you just want to give them an initial value and then read them.

2- properties and fields in your object are value type and they are not so large.

If that's the case you can take advantage of structs for a better performance and optimized memory allocation as they use only stacks rather than both stacks and heaps (in classes)




من مواصفات لغة C # :

1.7 الهياكل

مثل الطبقات ، والبنى هي هياكل البيانات التي يمكن أن تحتوي على أعضاء البيانات وأعضاء الوظيفة ، ولكن على عكس الطبقات ، والبنى هي أنواع القيمة ولا تتطلب تخصيص الكومة. يقوم متغير من نوع البنية بتخزين بيانات البنية بشكل مباشر ، بينما يقوم متغير من نوع الفئة بتخزين مرجع إلى كائن تم تخصيصه ديناميكياً. لا تدعم أنواع البنية الوراثة المحددة من قبل المستخدم ، وجميع أنواع البنية ترث ضمنيًا من كائن الكتابة.

تعد الهياكل مفيدة بشكل خاص لهياكل البيانات الصغيرة التي تحتوي على دلالات قيمة. الأرقام المعقدة ، النقاط في نظام إحداثيات ، أو أزواج القيم الرئيسية في القاموس هي كل الأمثلة الجيدة للبنى. يمكن استخدام بنية بدلاً من فئات بنية البيانات الصغيرة إحداث تغيير كبير في عدد عمليات تخصيص الذاكرة التي يقوم التطبيق بتنفيذها. على سبيل المثال ، يقوم البرنامج التالي بإنشاء وتهيئة مصفوفة من 100 نقطة. في حالة تنفيذ Point as a class ، يتم إنشاء مثيل لـ 101 كائنًا منفصلاً - أحدهما للصفيف والآخر لكل 100 عنصر.

class Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

class Test
{
   static void Main() {
      Point[] points = new Point[100];
      for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
   }
}

بديل هو جعل Point a struct.

struct Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

الآن ، يتم إنشاء مثيل كائن واحد فقط - واحد لصفيف - ويتم تخزين مثيلات نقطة في الخط في الصفيف.

يتم استدعاء منشئي البنية مع المشغل الجديد ، ولكن هذا لا يعني ضمناً أنه يتم تخصيص الذاكرة. بدلاً من تخصيص كائن بشكل حيوي وإرجاع مرجع إليه ، يقوم مُنشئ البنية ببساطة بإرجاع قيمة البنية نفسها (عادةً في موقع مؤقت على المكدس) ، ثم يتم نسخ هذه القيمة عند الضرورة.

مع الفصول ، من الممكن أن يقوم متغيرين بالإشارة إلى نفس الكائن ، وبالتالي يمكن أن تؤثر العمليات على متغير واحد على الكائن المشار إليه بواسطة المتغير الآخر. مع التركيبات ، يكون لكل متغير نسخة خاصة به من البيانات ، وليس من الممكن أن تؤثر العمليات على أحدهما على الآخر. على سبيل المثال ، يعتمد الإخراج الناتج من جزء التعليمات البرمجية التالي على ما إذا كانت Point فئة أو بنية.

Point a = new Point(10, 10);
Point b = a;
a.x = 20;
Console.WriteLine(b.x);

إذا كانت Point هي فئة ، فإن الناتج هو 20 لأن a و b يشيران إلى نفس الكائن. إذا كانت Point هي بنية ، فسيكون الناتج 10 لأن تخصيص a إلى b ينشئ نسخة من القيمة ، ولا تتأثر هذه النسخة بالتخصيص التالي للفأس.

يوضح المثال السابق اثنين من قيود البنيات. أولاً ، عادةً ما يكون نسخ بنية بأكملها أقل كفاءة من نسخ مرجع كائن ، لذا يمكن أن يكون تمرير المهمة وقيمة المعلمة أكثر تكلفة بالبنى من الأنواع المرجعية. ثانيًا ، باستثناء المعلمات المنقحة والخارجة ، لا يمكن إنشاء إشارات إلى البُنى ، التي تستبعد استخدامها في عدد من المواقف.




My rule is

1, Always use class;

2, If there is any performance issue, I try to change some class to struct depending on the rules which @IAbstract mentioned, and then do a test to see if these changes can improve performance.




Structure types in C# or other .net languages are generally used to hold things that should behave like fixed-sized groups of values. A useful aspect of structure types is that the fields of a structure-type instance can be modified by modifying the storage location in which it is held, and in no other way. It's possible to code a structure in such a way that the only way to mutate any field is to construct a whole new instance and then use a struct assignment to mutate all the fields of the target by overwriting them with values from the new instance, but unless a struct provides no means of creating an instance where its fields have non-default values, all of its fields will be mutable if and if the struct itself is stored in a mutable location.

Note that it's possible to design a structure type so that it will essentially behave like a class type, if the structure contains a private class-type field, and redirects its own members to that of the wrapped class object. For example, a PersonCollection might offer properties SortedByName and SortedById , both of which hold an "immutable" reference to a PersonCollection (set in their constructor) and implement GetEnumerator by calling either creator.GetNameSortedEnumerator or creator.GetIdSortedEnumerator . Such structs would behave much like a reference to a PersonCollection , except that their GetEnumerator methods would be bound to different methods in the PersonCollection . One could also have a structure wrap a portion of an array (eg one could define an ArrayRange<T> structure which would hold a T[] called Arr , an int Offset , and an int Length , with an indexed property which, for an index idx in the range 0 to Length-1 , would access Arr[idx+Offset] ). Unfortunately, if foo is a read-only instance of such a structure, current compiler versions won't allow operations like foo[3]+=4; because they have no way to determine whether such operations would attempt to write to fields of foo .

It's also possible to design a structure to behave a like a value type which holds a variable-sized collection (which will appear to be copied whenever the struct is) but the only way to make that work is to ensure that no object to which the struct holds a reference will ever be exposed to anything which might mutate it. For example, one could have an array-like struct which holds a private array, and whose indexed "put" method creates a new array whose content is like that of the original except for one changed element. Unfortunately, it can be somewhat difficult to make such structs perform efficiently. While there are times that struct semantics can be convenient (eg being able to pass an array-like collection to a routine, with the caller and callee both knowing that outside code won't modify the collection, may be better than requiring both caller and callee to defensively copy any data they're given), the requirement that class references point to objects that will never be mutated is often a pretty severe constraint.









Links



Tags

c# c#   struct