Классы vs Структуры
От: shapovalov Канада https://www.yaplex.com
Дата: 10.03.10 13:43
Оценка:
Привет,

у меня от предыдущего программиста осталась структура. Вот не могу понять, а почему она структура? почему не был использован класс?
назначение: у пользователей есть ID число но в некоторых местах программы работа идет с числом, а в некоторых со строкой, поэтому приходится постоянно конвертировать одно к другому, для этого была введена эта структура, которая умеет сама конвертировать куда нужно.
например такой id "32344232" или такая строка "000323323"

методов не много: Operator decimal, tostring()... пара конструкторов.

Так вот вопрос, когда и почему выгоднее использовать структуры вместо классов? ну про то что они хранятся в стеке и работы с ними идет быстрее я знаю, но может есть еще какие то причины сделать выбор в пользу структур?

Спасибо.
.NET Software developer @ www.yaplex.com
Re: Классы vs Структуры
От: Mr.Cat  
Дата: 10.03.10 13:58
Оценка:
Здравствуйте, shapovalov, Вы писали:
S>но может есть еще какие то причины сделать выбор в пользу структур?
Взгляни: http://msdn.microsoft.com/en-us/library/y23b5415%28VS.71%29.aspx

It is recommended that you use a struct for types that meet any of the following criteria:
* Act like primitive types.
* Have an instance size under 16 bytes.
* Are immutable.
* Value semantics are desirable.

Не истина в первой инстанции, конечно, но по идее логично.
Re: Классы vs Структуры
От: MozgC США http://nightcoder.livejournal.com
Дата: 10.03.10 14:20
Оценка: 5 (1)
Более-менее подробно можно прочитать в книге Framework Design Guidelines, в разделе 4.2 — Choosing between class and struct.

4.2 Choosing Between Class and Struct

One of the basic design decisions every framework designer faces is whether to design a type as a class (a reference type) or as a struct (a value type). Good understanding of the differences in the behavior of reference types and value types is crucial in making this choice.
Reference types are allocated on the heap, and garbage-collected, whereas value types are allocated either on the stack or inline in containing types and deallocated when the stack unwinds or when their containing type gets deallocated. Therefore, allocations and deallocations of value types are in general cheaper than allocations and deallocations of reference types.
Arrays of reference types are allocated out-of-line, meaning the array elements are just references to instances of the reference type residing on the heap. Value type arrays are allocated in-line, meaning that the array elements are the actual instances of the value type. Therefore, allocations and deallocations of value type arrays are much cheaper than allocations and deallocations of reference type arrays. In addition, in a majority of cases value type arrays exhibit much better locality of reference.

RICO MARIANI: The preceding is often true but it's a very broad generalization that I would be very careful about. Whether or not you get better locality of reference when value types get boxed when cast to an array of value types will depend on how much of the value type you use, how much searching you have to do, how much data reuse there could have been with equivalent array members (sharing a pointer), the typical array access patterns, and probably other factors I can't think of at the moment. Your mileage might vary but value type arrays are a great tool for your toolbox.

CHRIS SELLS: I find the restrictions of value types to be painful and therefore prefer reference types. Custom value types are often used for performance improvements, so I would recommend profiling large-scale anticipated usage of your library and changing reference type to value types based on actual data instead of on some anticipated problem that may never manifest itself in real-world conditions.

The next difference is related to memory usage. Value types get boxed when cast to a reference type or one of the interfaces they implement. They get unboxed when cast back to the value type. Because boxes are objects that are allocated on the heap and are garbage-collected, too much boxing and unboxing can have a negative impact on the heap, the garbage collector, and ultimately the performance of the application. In contrast, no such boxing occurs as reference types are cast.
Next, reference type assignments copy the reference, whereas value type assignments copy the entire value. Therefore, assignments of large reference types are cheaper than assignments of large value types.
Finally, reference types are passed by reference, whereas value types are passed by value Changes to an instance of a reference type affect all references pointing to the instance. Value type instances are copied when they are passed by value. When an instance of a value type is changed, it of course does not affect any of its copies. Because the copies are not created explicitly by the user but arc implicitly created when arguments are passed or return values are returned, value types that can be changed can be confusing to many users. Therefore, value types should be immutable.

RICO MARIANI: If you make your value type mutable you will find that you end up having to pass it by reference a lot to get the semantics you want (using, e.g., “out” syntax in C#). This might be important in cases in which the value type is expected to be embedded in a variety of other objects that are themselves reference types or embedded in arrays. The biggest
trouble from having mutable value types is where they look like independent entities like, for example, a complex number. Value types that have a mission in life of being an accumulator of sorts or a piece of a reference type have fewer pitfalls for mutability.

VANCE MORRISON: Today all reference types have an overhead of 8 bytes (16 on 64 bit) per object. Thus if your application memory usage is dominated by a large number (> 1M) of small objects (< 16 bytes), you will "waste" a large fraction of your memory on object overhead. You can avoid this bv putting these objects into a value type array instead (which has 0 per object overhead).
You can even refer to these elements inside the array as if they were normal objects by making "smart pointer" value types. These types have two fields; the first is to the large array, and the second is to the index within the array. From a user's point of view, using these "smart pointers" is just like using normal reference types, but you have saved large amounts of memory.

The downside to this technique is that you don't get garbage collection on elements in your array Thus, this technique should be used only when that is not an issue (e.g., when you have a large read-only array of small structures).

As a rule of thumb, majority of types in a framework should be classes. There are, however, some situations in which the characteristics of a value type make it more appropriate to use structs.

✓ CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.

✗ AVOID defining a struct unless the type has all of the following characteristics:
• It logically represents a single value, similar to primitive types (int, double, etc.).
• It has an instance size under 16 bytes.
• It is immutable.
• It will not have to be boxed frequently.

In all other cases, you should define your types as classes.

JEFFREY RICHTER: In my opinion, a value type should be defined for types that have approximately 16 bytes or less. Value types can be more than 16 bytes if you don't intend to pass them to other methods or copy them to and from a collection class (like an array). I would also define a value type if you expect instances of the type to be used for short periods of time (usually they are created in a method and no longer needed after a method returns). I used to discourage defining value types if you thought that instances of them would be placed in a collection due to all the boxing
that would have to be done. But, fortunately, newer versions of the CLR, C#, and other languages support generics so that boxing is no longer necessary when putting value type instances in a collection.

ERIC GUNNERSON: Rather than avoiding all value types that are bigger than 16 bytes in size, use this guideline as a trigger to do more investigation. Figure out how your type is used and do some benchmarking to understand what implications a bigger value type might have.
Also consider a value type if it is part of a set of types where all the others are value types. Having one reference type in such a group will likely be confusing.

JOE DUFFY: I frequently struggle with the reference versus value type decision. Although these rules are very black-and-white, there is a fairly large cliff you jump off of when you decide to implement a reference type. This decision means you will pay the cost of heap allocation for each instance—which can impact scalability on multiprocessor machines due to the shared heap and cost of collections—in addition to at least a pointer of overhead (due to the object header) and a level of indirection to each access (due to the need to go through an object reference). That said, my experience has shown that whenever I attempt to be clever and break any of these rules, it usually comes back to bite me.

Re: Классы vs Структуры
От: shapovalov Канада https://www.yaplex.com
Дата: 10.03.10 15:12
Оценка:
Спасибо за помощь.
вобщем понятно почему,
тип маленький, и используется везде так же как и decimal, так что наверное поэтому и была выбрана структура.
.NET Software developer @ www.yaplex.com
Re[2]: Классы vs Структуры
От: 0x7be СССР  
Дата: 10.03.10 15:15
Оценка: +1
Здравствуйте, Mr.Cat, Вы писали:

MC>

MC> ...
MC> * Are immutable.
MC> ...

Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации. Зачем копировать туда-сюда одну и ту же иммутабельную информацию?
Re[3]: Классы vs Структуры
От: cadet354 Россия
Дата: 10.03.10 15:55
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, Mr.Cat, Вы писали:


MC>>

MC>> ...
MC>> * Are immutable.
MC>> ...

0>Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации.
это как? если он иммутабельный то экземпляр не разделяется, он копируется!
0> Зачем копировать туда-сюда одну и ту же иммутабельную информацию?
ага, лучше отлавливать а кто же изменил поле в этом экземпляре, иммутабельность в многопоточных программах играет важную роль.
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[4]: Классы vs Структуры
От: 0x7be СССР  
Дата: 10.03.10 16:16
Оценка:
Здравствуйте, cadet354, Вы писали:

0>>Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации.

C>это как? если он иммутабельный то экземпляр не разделяется, он копируется!
Так и я о чем — зачем его копировать-то? Пусть все ссылаются на один и тот же объект!

C>ага, лучше отлавливать а кто же изменил поле в этом экземпляре, иммутабельность в многопоточных программах играет важную роль.

Как кто-то может изменить поле в иммутабельном классе?
Что ты понимаешь под словом "иммутабельность"?
Re[5]: Классы vs Структуры
От: cadet354 Россия
Дата: 11.03.10 07:03
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, cadet354, Вы писали:


0>>>Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации.

C>>это как? если он иммутабельный то экземпляр не разделяется, он копируется!
0>Так и я о чем — зачем его копировать-то? Пусть все ссылаются на один и тот же объект!
ясно,понятно

C>>ага, лучше отлавливать а кто же изменил поле в этом экземпляре, иммутабельность в многопоточных программах играет важную роль.

0>Как кто-то может изменить поле в иммутабельном классе?
0>Что ты понимаешь под словом "иммутабельность"?
поведение подобное string, datetime and etc.
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[3]: Классы vs Структуры
От: Mr.Cat  
Дата: 15.03.10 21:34
Оценка:
Здравствуйте, 0x7be, Вы писали:
MC>>

MC>> ...
MC>> * Are immutable.
MC>> ...

0>Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации. Зачем копировать туда-сюда одну и ту же иммутабельную информацию?

А фиг его знает, что авторы имели в виду. Возможно, хотели сказать, что структура и так ведет себя не так, как нормаль^W класс, а если ее еще и мутабельной сделать — так вообще. Вон, например, если мутабельную структуру пропертёй сделать, получим неюзабелную хрень:
struct S
{ /*public mutable stuff*/ }

class C
{
  S PropS { get; set; }
}


А с иммутабельностью, возможно, еще порешили так. Раз иммутабельный, значит часто создаются новые члены, причем многие — временные (ну, например var immutableStuff = s1.immutate(s2).immutate(s3)). Стало быть, нефиг мучить аллокатор и GC — можно всю временную фигню на стеке держать. Рразве что копировать накладно — вот и рекомендуют, мол, иммутабельность иммутабельностью, а шоб не больше 16 байт.
Re[3]: Классы vs Структуры
От: fmiracle  
Дата: 23.03.10 12:45
Оценка: 9 (1)
Здравствуйте, 0x7be, Вы писали:

0>Я думаю, что это как раз аргумент против структур. Если тип иммутабельный, то один экземпляр может разделятся сколь угодно большим числом потребителей без опасности нежелательной модификации. Зачем копировать туда-сюда одну и ту же иммутабельную информацию?


Думаю, в данном пункте авторы исходили из концепции наименьшей неожиданности, а не производительности.

Если структура мутабельна, то изменение ее поля в основном коде метода ведет к ее изменению. А изменение ее поля в методе, куда она передана параметром — не ведет к ее изменению в исходном коде (совершенно естественно — она же была туда откопирована).

При рефакторинге же можно не заметить, что данный объект — структура, а не класс, использовать его как класс, ожидая что он будет передан по ссылке и изменен в вызывающем методе и получить неожиданную плохозаметную ошибку.
С иммутабельным объектом (что класс, что структура) этой проблемы нет, и случайно перепутать — не получится.


Ну а ссылка из многих мест на один и тот же объект, в случае, когда он мелкий (до 16 байт по предыдущему пункту) — не несет особого выигрыша в плане производительости — сами ссылки плюс нагрузка на сборку мусора перекроект пользу от экономии за счет разделения объекта.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.