What are the disadvantages of using records instead of classes? - c#-9.0

C# 9 introduces record reference types. A record provides some synthesized methods like copy constructor, clone operation, hash codes calculation and comparison/equality operations. It seems to me convenient to use records instead of classes in general. Are there reasons no to do so?
It seems to me that currently Visual Studio as an editor does not support records as well as classes but this will probably change in the future.

Firstly, be aware that if it's possible for a class to contain circular references (which is true for most mutable classes) then many of the auto generated record members can StackOverflow. So that's a pretty good reason to not use records for everything.
So when should you use a record?
Use a record when an instance of a class is entirely defined by the public data it contains, and has no unique identity of it's own.
This means that the record is basically just an immutable bag of data. I don't really care about that particular instance of the record at all, other than that it provides a convenient way of grouping related bits of data together.
Why?
Consider the members a record generates:
Value Equality
Two instances of a record are considered equal if they have the same data (by default: if all fields are the same).
This is appropriate for classes with no behavior, which are just used as immutable bags of data. However this is rarely the case for classes which are mutable, or have behavior.
For example if a class is mutable, then two instances which happen to contain the same data shouldn't be considered equal, as that would imply that updating one would update the other, which is obviously false. Instead you should use reference equality for such objects.
Meanwhile if a class is an abstraction providing a service you have to think more carefully about what equality means, or if it's even relevant to your class. For example imagine a Crawler class which can crawl websites and return a list of pages. What would equality mean for such a class? You'd rarely have two instances of a Crawler, and if you did, why would you compare them?
with blocks
with blocks provides a convenient way to copy an object and update specific fields. However this is always safe if the object has no identity, as copying it doesn't lose any information. Copying a mutable class loses the identity of the original object, as updating the copy won't update the original. As such you have to consider whether this really makes sense for your class.
ToString
The generated ToString prints out the values of all public properties. If your class is entirely defined by the properties it contains, then this makes a lot of sense. However if your class is not, then that's not necessarily the information you are interested in. A Crawler for example may have no public fields at all, but the private fields are likely to be highly relevant to its behavior. You'll probably want to define ToString yourself for such classes.

All properties of a record are per default public
All properties of a record are per default immutable
By default, I mean when using the simple record definition syntax.
Also, records can only derive from records and you cannot derive a regular class from a record.

Related

using List<ValueObject> inside an entity DDD

Can we use List<ValueObject> inside entity? or we should use them as List<entity>?
When I use 'List<Discount>' inside my 'Product' entity class, entity framework creates a 'Discount' table with a generated column id.
Is it OK that i have defined Discount as List of value objects?
When a value object is used as a list, is it better to use it as an entity with its identity?
The second question is about updating 'List<Discont>' inside entity. how can I update this value object list inside its entity( add,remove discount)?
thanks
As mentioned in the comments by #Ivan Stoev, your domain model is not your database model. You need to model your domain in an object-oriented way with, ideally, no regard for the database. BTW, having some identifier in a Value Object does not make it an Entity. An Entity would, however, always require a unique identifier within that entity set but an identifier isn't the defining factor to make a class an entity (that would be whether it has its own lifecycle).
In the real world one would need to be pragmatic about the general guidance. For instance, if you need an identifier of sorts for your value object then that is fine. However, it may be that there is already something there that may be used. In an OrderItem one would use the ProductId since there should only be a single item for each product. In your Discount scenario perhaps there is a DiscountType where only unique discount types are permitted. On the point of mutable value objects, the reason a value object is usually not mutable is that it represents a particular value. You would never change 10 since that would be another value. It would seem that one would be changing 10 to, say, 15 when you need 15 but, in fact, that 15 is another value object. Again, one would need to be pragmatic and in many circumstances we end up using a Value Object that isn't as primitive as a single value so it may make sense to alter something on the value object. An order item is certainly not an entity but one would need to change the Quantity on the item every-so-often. Well, that may be another discussion around Quote/Cart vs Order but the concepts are still applicable.
On another note, I tend to nowadays define any "value object" that exists only within an aggregate as a nested class within the aggregate. I would not have Order and OrderItem classes but instead an Item class within the Order class... Order.Item. That is a design choice though but I thought I'd mention it.

Problem with boundry for different aggregates

I have a problem with the boundaries of aggregates. I was trying to read about aggregates, aggregate roots, and boundaries, looking for some code examples but I still struggle with it.
The app that I'm working on is an app to manage architecture projects.
Among the screens in the app there will be a screen with all details for the selected project, and one with all jobs for the selected constructor.
I have one AggregateRoot - ArchitectureProject.It has an Architect, Stages, etc. and it has a list of ConstructorJobs (as it has to be on the screen with project details). ConstructorJob has its name, some value, and a Constructor. A Constructor can have some ConstructorType. As for me, Constructor is another AggregateRoot. I have a problem with ConstructorJob. Where should I place it? What should be responsible for managing it?
I was trying to thing what cannot exist with what, and ConstructorJob cannot exists without Project, but on the other hand it has to have Constructor as well...
I can't imagine that Constructor would belong to Project Aggregate, as ConstructorType would be 4th level child to id, so searching for all constructors of that type would be painful, wouldn't be?
I would appreciate any explanation, how to handle such cases.
I think you are missing an important rule which usually makes your life a lot easier:
Rule: Reference Other Aggregates by Identity
See also Vaughn Vernon's Book Implementing Domain-Driven Design, chapter 10 - Aggregates.
It is important to note that Aggregates in the sense of domain-driven design are not so much focused on if the existence of one aggregate makes sense without the other. It is more about transactional boundaries. So an aggregate should create a boundary around elements that should only change together within the same transaction - to adhere to consistency.
So I guess, that you will change your Project in different use cases you would change the Constructor - which I guess can be referenced in different projects.
This means you should reference other aggregates within aggregates only by id which avoids modelling huge aggregates with deep hierarchies. It also means that if your aggregates tend to grow bigger over time that you might have missed some new aggregate which you initially modelled as entity and should be an aggregate on its own.
As for me, Constructor is another AggregateRoot. I have a problem with ConstructorJob. Where should I place it? What should be responsible for managing it?
In your case I would model it the following way:
The ConstructorJob is a Value Object which holds some data (name, etc.) and also a reference to a Constructor aggregate. But this reference is not a reference in terms of object reference like you would do it with a child entity of an aggregate root. The constructor aggregate is referenced by an identifier (UUID, integer or whatever you are using as id type) in the ConstructorJob.
The ConstructorJob value object would be part of the Project aggregate. The project aggregate could of course directly hold the id of the constructor aggregate but I guess in your case the value object might fit quite well.

When and why use anonymous class instead of stucts for simple objects

I read in this answer A generic list of anonymous class how to load a list with anonymous class objects. My question is why and when is recommendable to use this way instead of using a struct, considering performance and good practices.
An exposed-field structure is essentially a group of variables bound together with duct tape. It won't behave as an "object", and may thus be seen as evil who think everything should behave like an object; nonetheless, in cases where one doesn't really want an object, but rather a group of variables bound together with duct tape, an exposed-field structure may be a perfect fit.
Anonymous classes have only a few advantages over exposed-field structures:
The syntax to declare them is at least slightly smaller; depending upon coding standards, it may be a lot smaller. If coding standards will allow one to write internal struct WeightAndVolume { public double weight, volume;} and say that the struct is "self-explanatory" [it contains two public fields of type double, named weight and volume, each of which will hold whatever was last written to it by outside code], anonymous classes won't save much, but if coding standards would require that every named data type have many pages of associated documentation, including an analysis of required unit-test procedures, anonymous classes could avoid such hassle.
Copying class references is slightly cheaper than copying structures larger than 8 bytes, though unless a reference would be copied many times, the cost of creating the object will outweigh any savings in copying.
Casting an anonymous class to Object is much cheaper than casting a struct. The first time an anonymous class instance gets cast to Object will make up for the extra costs of creating it. Every additional time will represent a savings of that amount.
Passing a structure to a generic method will require the JITter to produce a specialized version of the code for that type; by contrast, the JITter would only have to produce one piece of code to handle all anonymous classes.
In general, structures will work better than anonymous classes. On the other hand, there are a few scenarios (mostly related to the third point above) where classes can end up being much better.
I wouldn't say it is ever recommended to use anonymous classes, in the sense that it's never wrong to not use them. But they typically get used when
it's an one-shot job, for which creating a proper named type would be cumbersome, and
the consumer of the objects is either compiler-generated code (you don't have access to the types backing those anonymous classes, but the compiler does) or uses reflection (in which case you don't need access to the types at compile time)
The most common scenario where this occurs is in LINQ queries.

Aggregate class extending base class - Violation of LSP?

The Liskov Substitution Principle (LSP) on Wikipedia
Say I have a Alien class with an numFingers attribute*. Occasionally, I need to pull the sum of the numFingers from the database, grouped by other field values. In these cases, I have no need to manipulate each record individually, but I do need access to a lot of their functionality -- be able to get attributes, perform some basic logic on them, etc. This may include data summed from thousands of records, so it makes little sense to instantiate thousands of Alien objects when the database query can do the work of summing for me.
I would like to make an extension class called AlienAggregate, whose attributes are set from the grouped & summed query. This class would allow me to call any of Alien's methods. The only difference between functionality of the two classes, is GetID(). The aggregate class has no ID, since its data has been derived from any number of records. Because of this, calling GetID() on AlienAggregate throws an exception.
Is this a violation of the Liskov Substitution Principle? Is there a better way to handle a call to GetID()? Is there a better way to design the relationship between the Alien and AlienAggregate classes?
*Actual names may have been changed just because I can.
I don't think you're violating LSP since the principle only applies when Alien is a subtype of AlienAggregate (or the other way around). There is no is a relationship here (more of an aggregation of Alien's as you've appropriately named them).
Instead, it sounds like both Alien, and AlienAggregate probably implement a LooksAlien Interface. The Alien class just has an additional method, GetID().
...just beware of the nefarious BeginInvasion method on AlienAggregate.

How to serialize two different sets of fields of an object

I have a some classes which I need to serialize in two different ways: first- "basic" fields, and the second- some other fields.
e.g. a User class which I sometimes need to serialize just the "first name" and "last name" fields, and sometimes I need to serialize the "id" and "email"
fields as well.
The best way I found to do this so far is mark the basic fields with the [DataMember] attribute, and let .NET do the serializing for me, and for the rest
mark them with a customize attribute and do the serialization myself.
This solution proved to be very costly:
I first sirialize the basic attributes (as mentioned, .NET does that for me)
Then I get the property names of the fields marked with the custom attribute (using reflection namespace),
Then I try to get the those fields and their values from the object, and add their serialization to the basic serialization (not very successfully so far).....
Question is:
Is there a better way? preferbly by which .NET will do the rest of the work for me, and if not, at least one by which I don't need to go through all the
object's fields, find the relevant ones and serialize them myself..
Thank you all..
Oren,
Are you having to run these operations 1000x or more per minute? If not, all but the clumsiest of solutions will not be too costly. For exmample, if you need to do it like this, working from 2 objects is probably just fine. if you haven't actually run real timing comparisons, there's a huge chance you're wrong about what's expensive and what isn't.
But if you want to do it like this anyway, here is a solution that will only take 1% more time.
have an object, e.g., Core, for the subset, and Full for the whole thing
in the constructor of Full, instantiate a private instance of Core (composition pattern sort of). This has insignificant overhead.
Full will not have private member variables for the Core members. Full's setters and getters of the core data will refer to the private instance of Core. So no overhead.
Now you have 2 objects to serialize.