Skip to content

Record types

Leonid Gordo edited this page Oct 13, 2017 · 4 revisions

The record is a collection of fields and properties possibly of different data types. The record type is a data type that describes such records. The type provides a number of frequently-used operations out-of-box: equality, calculation of the hash value, representing of stored values as a string. Unfortunately, nowadays C# compilers does not support such types as first-class citizens. The library closes this gap.

To create a record you should write a simple class based on generic abstract class named Record<>.

public class Person : Record<Person>
{
	public string FirstName {get;set;}		
	public string LastName {get;set;}	
	public Gender Gender {get; set;}		
	public DateTime Birthdate {get;set;}
}

Since then, any instance of Person can be compared for equality, used as key for hash tables or dictionaries and its content can be serialized to string representation.

var person = new Person
{
	FirstName = "John",
	LastName = "Brown",
	Gender = Gender.Male,
	Birthdate = new DateTime(1985, 03, 15)
};

person.Equals(otherPerson) will check wheither all fields of this record match to ones of another record. person.GetHashCode() will calculate hash code for the record based on the hash codes of all fields of the record. And person.ToString() output is below:

FirstName :	John
LastName :	Brown
Gender :	<Gender>
	Male
Birthdate :	<DateTime>
	15.03.1985 0:00:00

As you can see the output renders the primary types as is and unwraps the complex types like other classes. Record support nullable types as well.

public class Person : Record<Person>
{
	public string FirstName {get;set;}		
	public string LastName {get;set;}	
	public Gender Gender {get; set;}		
	public DateTime? Birthdate {get;set;}
}
	
var person = new Person
{
	FirstName = "John",
	LastName = "Brown",
	Gender = Gender.Male
};

Here is the output of ToString() call.

FirstName :	John
LastName :	Brown
Gender :	<Gender>
	Male
Birthdate :	(null)

If you intend to select specific fields to be used in specific operation or exclude some fields from specific operation then you can use Enable***Attribute and Disable***Attribute attributes. These attributes can be applied to the entire record type and to specific members as well. Full list of attributes is below.

Attribute Meaning
EnableEqualityAttribute Enables the equality operation for specific type or member of type
DisableEqualityAttribute Disables the equality operation for specific type or member of type
EnableGetHashCodeAttribute Enables the calculation of hash code for specific type or member of type
DisableGetHashCodeAttribute Disable the calculation of hash code for specific type or member of type
EnableToStringAttribute Enables the serialization of specific type or member of type to the string representation
DisableToStringAttribute Disables the serialization of specific type or member of type to the string representation
EnableMergeAttribute Enables the merge of specific type or member of type
DisableMergeAttribute Disables the merge of specific type or member of type

The attribute applied to the specific member of type overrides the application of the same attribute class (equality, get hash code, to string or merge) to this type. For example, if you intend to check the equality of two person only by first and last names then you can mark entiry record with DisableEqualityAttribute and mark the specific fields or properties with EnableEqualityAttribute.

[DisableEquality]
public class Person : Record<Person>
{
	[EnableEquality] public string FirstName {get;set;}		
	[EnableEquality] public string LastName {get;set;}	
	public Gender Gender {get; set;}		
	public DateTime Birthdate {get;set;}
}

Records merging

It is possible to merge two records of the same type into single one. The operation takes first record and copies the defined values into new one. Then operation takes second one and copies the defined values that were undefined in the first one. The result will contain values from both records.

var personsWithGender = GetPersonsWithGenderSet();
var personsWithBirdthdate = GetPersonsWithBirthdateSet();
var persons = personsWithGender.Join(personsWithBirdthdate, 
	p => p, p => p, (p1, p2) => p1.Merge(p2), typeof(Person)); 

In this scenario, GetPersonsWithGenderSet returns a collection of persons with gender property set, and GetPersonsWithBirthdateSet returns a collection of same persons with birthdate property set. Then we join both collections into single one using built-in record type comparer and merging properties that were leaved undefined after each method calls. The result is the collection of persons with gender and birthdate properties both set.

Clone this wiki locally