As per previous post, when passing either an entity or its ID to a method, we could convert the type to a struct (from an interface) to avoid boxing.
This post will not make much sense unless you’ve read the previous one. (And even then, it won’t make any sense unless you’re writing database code in C#…)
We’d defined a type IdOrEntity<T>
allowing an API method to accept either an entity object or its ID. The method could then fetch the entity if an ID was provided, or directly use the entity if an entity was provided. If this is happening a lot in a code base, we should probably avoid the continual boxing, and instead declare IdOrEntity<T>
as:
public class Entity<K, E>...
{
public readonly struct IdOrEntity {
public IdOrEntity(ID id, Entity<K, E>? entity = null) {
Id = id;
EntityOrNull = entity;
}
public ID Id { get; }
public Entity<K, E>? EntityOrNull { get; }
}
public static implicit operator IdOrEntity(Entity<K, E> entity) =>
new IdOrEntity(entity.Id, entity);
public static implicit operator IdOrEntity(ID id) =>
new IdOrEntity(id);
public static implicit operator ID(IdOrEntity idOrEntity) =>
idOrEntity.Id;
}
Instead of inheritance, we use implicit conversions to derive IdOrEntity
values which may also be implicitly converted back into ID
instances.