My scenario:
public class EntityBase
{
public int ID { get; set; }
[Required()]
public string Name { get; set; }
//And this is what is getting me
//I want a "Type" enum
}
Then derived classes would have different enums that they would assign to Type.
public class AnimalEntity : EntityBase
{
//Type would have an 'animal type' value: Land, Sea or Air
//Implementation code would do something like:
// myAnimal.Type = AnimalType.Land
}
public class PersonEntity : EntityBase
{
//Type would have a 'person type' value: Doctor, Lawyer or Engineer
//Implementation code would do something like:
// myPerson.Type = PersonType.Lawyer
}
public class MonsterEntity : EntityBase
{
//Type would have a 'monster type' value: Goblinoid, Undead
}
So, the big question is what am I trying to do, right? I am trying to create a base repository class, which will return entities grouped by type. All my entities will have some kind of "type", and I want to create a generic "group by type".
public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : EntityBase
{
//Our common GetAsync, GetByIdAsync, and all our other CRUD
//And then something like this:
public IEnumerable<GroupedData<string, T>> GetGroupedByType(string searchTerm)
{
var entities =
from s in DbSet
where (searchTerm == null || s.Name.ToLower().Contains(searchTerm))
group s by s.Type into g
select new GroupedData<string, T> { Key = g.Key.ToString(), Data = g };
return (entities);
}
}
When T is AnimalEntity, I would get groups Land, Sea and Air with the corresponding entities. For PersonEntity, I would get Doctor, Lawyer, Engineer groups.
If my approach/design is invalid or less than ideal, please let me know.
Enum (please pardon me) are kind of second class citizens so first thing you may think about will not work:
class EntityBase<T> where T : enum {
public T Type { get; set; }
}
Unfortunately it doesn't compile, you may then think to replace enum with a base class:
class EntityBase<T> where T : EntityTypeBase {
public T Type { get; set; }
}
Implementing in EntityTypeBase everything you need to be comfortable with them (== and != operators, IConvertible interface and other boilerplate). It's a lot of code and you'll need also to manage that in EF (otherwise you won't be able to use such property in your queries unless you load everything in memory as objects). You may also force the use of enums (with a run-time check) but this will break SQL code generation in EF.
What's I'd suggest in this case is to use a type EF knows and understand. You may use a string (if you wish so) or an integer (as in this example):
class EntityBase
public virtual int Type { get; set; }
}
In a derived class:
class AnimalEntity : EntityBase {
public override int Type {
get { return base.Type; }
set {
if (!Enum.IsDefined(typeof(AnimalType), value))
throw new ArgumentException();
base.Type = (int)value;
}
}
}
In this way you still can use PersonType.Layer and AnimalType.Land keeping also a little of type safety. Of course you need to keep your enums in-sync to do not have duplicated values (otherwise group by won't work).
As last please also consider to use...another entity. If you have another table EntityType:
ID Name ApplicableTo
0 Laywer Person
1 Programmer Person
2 Land Animal
...
What you have to do in the setter is to check if type is applicable or not and you may have few convenience classes that will group them by type:
public static class PersonType {
public static EntityType Lawyer { get { ... } }
public static EntityType Programmer { get { ... } }
}
IMO this is scale better (easier to add new items and you can delegate, in future, some behavior to EntityType items) and it is safer than hard-coded constants (because integrity is granted by DB engine itself). Of course price to pay is extra overhead for the search in the EntityType table (unless you use some caching mechanism).
Two options I can think of:
First, preferably, use a generic type parameter (T in this sample):
public class EntityBase<T>
{
public T Type {get;set;}
}
Supply that type in the type declaration:
public class AnimalEntity : EntityBase<AnimalEnum>
{ }
Second, if you need more freedom, I usually use a list of string contants:
public class EntityBase
{
public string Type {get;set;}
}
public static class AnimalTypes
{
public const string Dog = "dog";
public const string Cat = "cat";
}
Related
I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.
I have the following interfaces:
public abstract class Identity<T>
{
protected abstract string GetIdentity();
}
public interface IAggregate<T>
{
Identity<T> Identity { get; }
}
public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}
I implement with the below:
public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}
public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}
public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}
Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).
public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}
That gives me the code:
public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}
So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.
What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.
I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.
Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.
I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:
public interface IDomainEventHandler<TIdentity, TEvent>
where TIdentity : IIdentity
where TEvent : IDomainEvent
{
void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
}
I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).
The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.
Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.
All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).
public interface IDomainEvent
{
DateTime OccurredOn { get; set; }
Guid MessageId { get; set; }
}
public class TestUserCreated : IDomainEvent
{
// id can be accessed by whatever needs it by being
// defined explicity within the domain event POCO
// without needing any base class or framework.
public readonly TestUserId Id;
public readonly string Name;
public TestUserCreated(TestUserId id, string name)
{
Id = id;
Name = name;
}
}
Short version:
I have an abstract class A. It has a method that needs to know the value of a static class property that is specific to each subclass. The name and type is the same, just the value can be unique for each subclass.
Can I define this static property in the base class A to be able to access it with methods defined in A, but keeping the property's values of different subclasses unrelated?
Or how would I implement something like that?
Long version:
Let's say I have an abstract base class for data models. It has a public property Id (Int32).
I would like to implement a constructor in the base class that generates a new ID based on the last assigned ID for objects of a subclass.
The reason is that the real IDs are assigned automatically by the database, but each data model object already has to have a unique ID when it gets constructed without being written to the database yet. As the database assigns only positive integers as ID, my plan is to assign newly created data model objects a temporary, unique negative ID. As soon as the object gets written, the ID will get changed to the real one.
As I have quite a few different data model classes all deriving from my abstract base class, I thought it would be good to include that functionality there to not duplicate it. But each subclass has to have their own counter that points to the next free negative ID, as the different classes' IDs are unrelated.
So I need a static property in each subclass storing this class' last assigned temporary ID, but the mechanism to assign it is always the same and could be implemented into the abstract base class' constructor. However, I can't access a property from the base class that has to be implemented by the subclasses, which means I have to define it in the base class. But will this static property then be global for all subclasses, which is not what I want?
How can I implement this temporary ID counter the most elegant way?
Simplified code example:
public abstract class ModelBase
{
public Int32 Id { get; set; }
protected static Int32 LastTempId { get; set; } = 0;
public ModelBase()
{
Id = --LastTempId;
}
}
public class Model1 : ModelBase
{
public Model1 () : base ()
{
// do something model1-specific
}
}
public class Model2 : ModelBase
{
public Model2() : base()
{
// do something model2-specific
}
}
If I implement it like this, I fear that for both subclasses model1 and model2, the inherited static property LastTempId will be the same instance. But I want a separate counter for each subclass while still using it in the base class constructor.
Short answer
The sub-classes cannot have different values for the static property because the static property is a property of the class, not of it's instances, and it's not inherited.
Long answer
You could implement a single counter on the abstract class as a static property and have one constructor of the abstract class using it.
EDIT: To save different counters for each sub-class you could use a static dictionary mapping a Type (sub-class) to a counter.
public abstract class A<T>
{
public static Dictionary<Type, int> TempIDs = new Dictionary<Type, int>();
public int ID { get; set; }
public A()
{
if (!TempIDs.ContainsKey(typeof(T)))
TempIDs.Add(typeof(T), 0);
this.ID = TempIDs[typeof(T)] - 1;
TempIDs[typeof(T)]--;
}
}
public class B : A<B>
{
public string Foo { get; set; }
public B(string foo)
: base()
{
this.Foo = foo;
}
}
public class C : A<C>
{
public string Bar { get; set; }
public C(string bar)
: base()
{
this.Bar = bar;
}
}
B b1 = new B("foo");
B b2 = new B("bar");
C c1 = new C("foo");
C c2 = new C("foo");
b1.ID would be -1, b2.ID would be -2, c1.ID would be -1 and c2.ID would be -2
First of all, my humble opinion is entities shouldn't be responsible of assigning their own unique identifier. Keep a clear separation of concerns.
There should be another player in that game that should assign those temporary unique identifiers (either if they're negative or positive integers).
Usually, that so-called other player is an implementation of repository design pattern which is responsible of translating the domain (your models) into the definitive representation of your data and vice versa.
Usually a repository has a method to add objects. And this should be the point where you set these temporary identifiers:
public void Add(Some some)
{
some.Id = [call method here to set the whole id];
}
And, most repository implementations are per entity.
CustomerRepository
InvoiceRepository
...
...but this doesn't prevent you from defining a base repository class which could implement what can be in common when handling some entity types:
public interface IRepository<TEntity> where TEntity : EntityBase
{
// Other repository methods should be defined here
// but I just define Add for the convenience of this
// Q&A
void Add(TEntity entity);
}
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : EntityBase
{
public virtual void Add(TEntity entity)
{
entity.Id = [call method here to set the whole id];
}
}
...and now any class deriving Repository<TEntity> will be able to generate a temporary identifier for their specialized entities:
public class CustomerRepository : Repository<Customer> { }
public class InvoiceRepository : Repository<Invoice> { }
How you could implement the unique and temporary entity identifier as part of the abstract repository class and being able to do so for each specific entity type?
Use a dictionary to store per-entity last assigned identifier implementing a property to Repository<TEntity>:
public Dictionary<Type, int> EntityIdentifiers { get; } = new Dictionary<Type, int>();
...and a method to decrease next temporary identifier:
private static readonly object _syncLock = new object();
protected virtual void GetNextId()
{
int nextId;
// With thread-safety to avoid unwanted scenarios.
lock(_syncLock)
{
// Try to get last entity type id. Maybe the id doesn't exist
// and out parameter will set default Int32 value (i.e. 0).
bool init = EntityIdentifiers.TryGetValue(typeof(TEntity), out nextId);
// Now decrease once nextId and set it to EntityIdentifiers
nextId--;
if(!init)
EntityIdentifiers[typeof(TEntity)] = nextId;
else
EntityIdentifiers.Add(typeof(TEntity), nextId);
}
return nextId;
}
Finally, your Add method could look as follows:
public virtual void Add(TEntity entity)
{
entity.Id = GetNextId();
}
One way to go is reflection, but it takes run-time and is prone to runtime errors. As others mentioned: you cannot force inheriting classes to redeclare some static field and be able to use this field in ancestor class. So I think minimal code redundancy is necessary: each inheriting class should provide it's own key generator. This generator can be kept in static field of the class of course.
(Note this is not necessarily thread-safe.)
class KeyGenerator
{
private int _value = 0;
public int NextId()
{
return --this._value;
}
}
abstract class ModelBase
{
private KeyGenerator _generator;
public ModelBase(KeyGenerator _generator)
{
this._generator = _generator;
}
public void SaveObject()
{
int id = this._generator.NextId();
Console.WriteLine("Saving " + id.ToString());
}
}
class Car : ModelBase
{
private static KeyGenerator carKeyGenerator = new KeyGenerator();
public Car()
: base(carKeyGenerator)
{
}
}
class Food : ModelBase
{
private static KeyGenerator foodKeyGenerator = new KeyGenerator();
public Food()
: base(foodKeyGenerator)
{
}
}
class Program
{
static void Main(string[] args)
{
Food food1 = new Food();
Food food2 = new Food();
Car car1 = new Car();
food1.SaveObject();
food2.SaveObject();
car1.SaveObject();
}
}
This produces:
Saving -1
Saving -2
Saving -1
Just generate a GUID for each object before it gets added to your database. You could have an isAdded flag that tells you the object should be referred to be GUID, or clear the GUID once the object is added. With a GUID you never have to worry that two objects will clash. Also it obviates the need for separate IDs per subclass. I would not reuse the same property for two states as you propose.
https://msdn.microsoft.com/en-us/library/system.guid(v=vs.110).aspx
Well, static classes aren't inherited, so that's out,m and you can't force subclasses to implement a static method, so that's out too.
Rather than putting that method in the class itself, why not have a base interface that you can implement. Then you can have an instance method that can be abstract:
public interface IDataModelFactory<T> where T:ModelBase
{
int GetLastTempId();
}
public Model1Factory : IDataModelFactory<Model1>
{
public int GetLastTempId()
{
// logic for Model1
}
}
public Model2Factory : IDataModelFactory<Model2>
{
public int GetLastTempId()
{
// logic for Model2
}
}
Or if the logic is common to all classes, have an abstract base class with (or without) the interface:
public DataModelFactory<T> : IDataModelFactory<T>
{
public virtual int GetLastTempId()
{
// common logic
}
// other common logic
}
You could even make the factories singletons so you don't have to create instances all the time, and they can even be sub-classes of the model classes so they're closely linked.
As a side note, if you're uncertain what the inheritance/interface relationship would be, I often find it's quicker start with copy/paste reuse and refactor your code to introduce base classes and interfaces. That way you know what the common code is and can refactor that into common methods. Otherwise you are tempted to try and put everything in the base class and use switches or other constructs to change logic based on the derived type.
I'm looking for a way to create a generic base class that has a typesafe taxonomy using internal properties.
Just to be clear, the class doesn't have to use the generics language feature as long as it is generic itself and I'm looking for something that has compile-time type safety.
As an example here is a simple taxonomy I want to represent using multiple instances of the same class
Wood
Crate
Box
Metal
Crate
Bar
The permutations of which are
Wood Crate
Wood Box
Metal Crate
Metal Bar
initially I though I could use enums to represent the different levels of taxonomy like so
public enum EFirstLevel
{
Wood,
Metal
}
public enum ESecondLevel
{
Crate,
Box,
Bar
}
public class BaseItem
{
EFirstLevel FirstLevel;
ESecondLevel SecondLevel;
public BaseItem(EFirstLevel aFirst, ESecondLevel aSecond)
{
FirstLevel = aFirst;
SecondLevel = aSecond;
}
}
I could create the items above using:
var item1 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Crate)
var item2 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Box)
var item3 = new BaseItem(EFirstLevel.Metal,ESecondLevel.Crate)
var item4 = new BaseItem(EFirstLevel.Metal,ESecondLevel.Bar)
but I could also create
var item5 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Bar)
which for my purposes is incorrect.
Do any of you know of a pattern that would let me create a single class to represent the example taxonomy in a type-safe way that prohibits the creation of incorrect combinations.
It also needs to be applicable to N levels of taxonomy, the 2 levels above are just an example.
Thank you
Update:
I do require compile-time type safety.
I could do this with multiple classes quite easily using inheritance and such, I'm trying to find a solution using instances of just a single base class.
let me know if you need any more info
Update:
#Maarten Yes, i'm trying to sure that the hierarchy is maintained so if EFirstLevel is 1 then ESecondLevel must be either Crate or Box.
Just to clairify i'm happy to have other supporting classes, what i'm trying to avoid is having to explicitly create a class for each taxanomic value.
What I'm trying to accomplish is providing an example layout of class that that maintains this taxanomic type safety so I can reflect over it and permute combinations. While maintaining the type safety should I need to generically instantiate said permutations.
The class upon which I might reflect could come form a third party and as such I might not know beforehand the values for each level.
I could generate all the possible combinations into a set of classes with type safe internal enums but this would require regeneration of said classes any time you changed the items in any level.
I was just wondering if there was a was to achieve my goals without having to generate any classes.
EDIT: Moved this section to an answer
I don't think you're going to be able to get away without creating classes/interfaces and having compile-time checks that that objects conform to your taxonomy.
I'd suggest a solution as follows:
// Define the taxonomic levels here. Each level (except the first) references its next-higher taxonomic level in a type constraint
interface Material { }
interface Object<TMaterial> where TMaterial : Material { }
// Define the items in the highest taxonomic level (materials)
interface Wood : Material { }
interface Metal : Material { }
// Define the items in the 2nd taxonomic level (objects), implementing the appropriate interfaces to specify what the valid top-level taxonomies it can fall under.
interface Crate : Object<Wood>, Object<Metal> { }
interface Bar : Object<Metal> { }
interface Box : Object<Wood> { }
// Define an item class with type constraints to ensure the taxonomy is correct
abstract class Item<TMaterial, TObject>
where TMaterial : Material
where TObject : Object<TMaterial>
{
}
With the above defined, we can now define valid items:
class MetalBar : Item<Metal, Bar> { }
class MetalCrate : Item<Metal, Crate> { }
class WoodCrate : Item<Wood, Crate> { }
class WoodBox : Item<Wood, Box> { }
However attempting to create an invalid item (e.g. a wooden bar) results in a compile time error:
class WoodBar : Item<Wood, Bar> { }
The type 'Taxonomy.Bar' cannot be used as type parameter 'TObject' in the generic type or method 'Taxonomy.Item'. There is no implicit reference conversion from 'Taxonomy.Bar' to 'Taxonomy.Object'
Two ways -
Create an enum which will contain the leaves of your tree, in your case Wood_Crate, Wood_box and so on. Easy to do and less easy to maintain or read.
Define a class called Category and a static class for each of the elements in your tree. For example
public class Category
{
internal Category() {};
public string Id; // This would be used to understand what you got, can be a list of enums or something
}
public static Category CrateCategory = new Category {Id = "Wood.Crate"};
public static class Wood
{
// either way will work, one will let you directly access CrateCategory (if that is what you wish), the second will remove the need for different Crate categories
public static Category Crate { get { return CrateCategory; } }
public static Category Box { get { return new Category { Id = "Wood.Box" }; } }
}
Your BaseItem constructor will only receive a Category. And could write something like
new BaseItem(Box.Crate);
If you place the Category class in another assembly, you will sure no one would be able to create their own Categories.
That's a bit more work, but seems more elegant and readable to me. If N is extremely large, you could write some code to generate the classes and Category identifiers for you.
My suggestion would be to create a class for each type and then let the valid subtype inherit from this type.
Finally edit the BaseItem type to be generic and only accept valid types.
Like this (Sorry bad at explaining)
class Wood {}
class Metal {}
class Crate : Wood, Metal {}
class Box : Wood {}
class Bar : Metal {}
class BaseItem<T1, T2> where T2 : T1
{
}
This will give you compile time type safety (but I don't think it's the best way)
Think I've found what I'm looking for
#Iridium had an answer close to what I think is going to be my solution, however rather than having to define each item as a class I think I've found a way to maintain the type safety and still be able to create the items as properties of a single base class.
As in #Iridium's answer it does require the creation of linked classes defining the taxonomic relationships.
Instead of using interfaces I remembered an SO answer I found a long time ago about pseudo enum inheritance with a protected constructor
Question is Here see the answer by "Seven"
If I define 2 base classes on which I can base the taxonomic chaining classes
public class ChainEnum
{
public int IntValue { get; protected set; }
public static readonly ChainEnum None = new ChainEnum(1);
protected ChainEnum(int internalValue)
{
this.IntValue = internalValue;
}
}
public class ChainLinkEnum<TParent> : ChainEnum where TParent : ChainEnum
{
public TParent Parent { get; protected set; }
protected ChainLinkEnum(int internalValue, TParent aParent)
: base(internalValue)
{
Parent = aParent;
}
}
I can then use these to chain as many levels deep as needed (for very deep trees this may not be ideal)
The first level inherits from the chain enum with no parent
public class HEBaseMaterial : ChainEnum
{
public static readonly HEBaseMaterial Wood = new HEBaseMaterial(1);
public static readonly HEBaseMaterial Metal = new HEBaseMaterial(1);
protected HEBaseMaterial(int internalValue) : base(internalValue) { }
}
Subsequent levels inherit from the chain link enum which defines a parent
public class HEWoodItemTypes : ChainLinkEnum<HEBaseMaterial>
{
private static readonly HEBaseMaterial InternalParent = HEBaseMaterial.Wood;
public static readonly HEWoodItemTypes Box = new HEWoodItemTypes(1);
public static readonly HEWoodItemTypes Crate = new HEWoodItemTypes(1);
protected HEWoodItemTypes(int internalValue) : base(internalValue, InternalParent)
{ }
}
public class HEMetalItemTypes : ChainLinkEnum<HEBaseMaterial>
{
private static readonly HEBaseMaterial InternalParent = HEBaseMaterial.Metal;
public static readonly HEMetalItemTypes Box = new HEMetalItemTypes(1);
public static readonly HEMetalItemTypes Bar = new HEMetalItemTypes(1);
protected HEMetalItemTypes(int internalValue) : base(internalValue, InternalParent) { }
}
A third level would use a signature like
public class HEThirdLevelType : ChainLinkEnum<HEWoodItemTypes>
After that set-up I can then define my single base item class like:
public class TwoLevelItem<T1,T2>
where T1 : ChainEnum
where T2 : ChainLinkEnum<T1>
{
public T1 LevelOne { get; set; }
public T2 LevelTwo { get; set; }
}
or if I wanted an item with 5 levels of taxonomy where each is linked to the one before
public class FiveLevelItem<T1,T2>
where T1 : ChainEnum
where T2 : ChainLinkEnum<T1>
where T3 : ChainLinkEnum<T2>
where T4 : ChainLinkEnum<T3>
where T5 : ChainLinkEnum<T4>
{
public T1 LevelOne { get; set; }
public T2 LevelTwo { get; set; }
public T3 LevelThree { get; set; }
public T4 LevelFour { get; set; }
public T5 LevelFive { get; set; }
}
or 3 properties with one first level and 2 second levels both linked to the first
public class LinkedItem<T1,T2_1,T2_2>
where T1 : ChainEnum
where T2_1 : ChainLinkEnum<T1>
where T2_2 : ChainLinkEnum<T1>
{
public T1 LevelOne { get; set; }
public T2_1 LevelTwoOne { get; set; }
public T2_2 LevelTwoTwo { get; set; }
}
Once the single base class is defined, i can reflect over it and the chain enums to get the permutations.
each item is created as a property
var metalBox = new TwoLevelItem<HEBaseMaterial,HEMetalItemTypes>()
{
LevelOne = HEBaseMaterial.Metal,
LevelTwo = HEMetalItemTypes.Box
}
This maintains the type safety and means that I can new properties to a taxonomy level and not have to create classes for items(although I do have to generate the extra items as properties)
This seems to do all i wanted but i've yet to try it extensively.
#Iridium's answer was close but not quite what I was looking for, although it did help.
I have several different entities in my domain model (animal species, let's say), which have a few properties each. The entities are readonly (they do not change state during the application lifetime) and they have identical behavior (the differ only by the values of properties).
How to implement such entities in code?
Unsuccessful attempts:
Enums
I tried an enum like this:
enum Animals {
Frog,
Duck,
Otter,
Fish
}
And other pieces of code would switch on the enum. However, this leads to ugly switching code, scattering the logic around and problems with comboboxes. There's no pretty way to list all possible Animals. Serialization works great though.
Subclasses
I also thought about where each animal type is a subclass of a common base abstract class. The implementation of Swim() is the same for all Animals, though, so it makes little sense and serializability is a big issue now. Since we represent an animal type (species, if you will), there should be one instance of the subclass per application, which is hard and weird to maintain when we use serialization.
public abstract class AnimalBase {
string Name { get; set; } // user-readable
double Weight { get; set; }
Habitat Habitat { get; set; }
public void Swim(); { /* swim implementation; the same for all animals but depends uses the value of Weight */ }
}
public class Otter: AnimalBase{
public Otter() {
Name = "Otter";
Weight = 10;
Habitat = "North America";
}
}
// ... and so on
Just plain awful.
Static fields
This blog post gave me and idea for a solution where each option is a statically defined field inside the type, like this:
public class Animal {
public static readonly Animal Otter =
new Animal
{ Name="Otter", Weight = 10, Habitat = "North America"}
// the rest of the animals...
public string Name { get; set; } // user-readable
public double Weight { get; set; }
public Habitat Habitat { get; set; }
public void Swim();
}
That would be great: you can use it like enums (AnimalType = Animal.Otter), you can easily add a static list of all defined animals, you have a sensible place where to implement Swim(). Immutability can be achieved by making property setters protected. There is a major problem, though: it breaks serializability. A serialized Animal would have to save all its properties and upon deserialization it would create a new instance of Animal, which is something I'd like to avoid.
Is there an easy way to make the third attempt work? Any more suggestions for implementing such a model?
If you have issues with serialization, you can always separate the application-code from the serialization code. That is, place conversion classes that convert to/from your serialized state. The serialized instances can have exposed any empty constructors and properties needed and their only job is to serialize state. Meanwhile, your application logic works with the non-serializable, immutable objects. This way you do not mix your serialization concerns with logical concerns which brings with it a host of disadvantages as you are finding out.
EDIT: Here's some example code:
public class Animal
{
public string Name { get; private set; }
public double Weight { get; private set; }
public Habitat Habitat { get; private set; }
internal Animal(string name, double weight, Habitat habitat)
{
this.Name = name;
this.Weight = weight;
this.Habitat = habitat;
}
public void Swim();
}
public class SerializableAnimal
{
public string Name { get; set; }
public double Weight { get; set; }
public SerializableHabitat Habitat { get; set; } //assuming the "Habitat" class is also immutable
}
public static class AnimalSerializer
{
public static SerializableAnimal CreateSerializable(Animal animal)
{
return new SerializableAnimal {Name=animal.Name, Weight=animal.Weight, Habitat=HabitatSerializer.CreateSerializable(animal.Habitat)};
}
public static Animal CreateFromSerialized(SerializableAnimal serialized)
{
return new Animal(serialized.Name, serialized.Weight, HabitatSerializer.CreateFromSerialized(serialized.Habitat));
}
//or if you're using your "Static fields" design, you can switch/case on the name
public static Animal CreateFromSerialized(SerializableAnimal serialized)
{
switch (serialized.Name)
{
case "Otter" :
return Animal.Otter
}
return null; //or throw exception
}
}
Then your application logic for serialization might look something like:
Animal myAnimal = new Animal("Otter", 10, "North America");
Animal myOtherAnimal = Animal.Duck; //static fields example
SerializableAnimal serializable = AnimalSerializer.CreateSerializable(myAnimal);
string xml = XmlSerialize(serializable);
SerializableAnimal deserialized = XmlDeserializer<SerializableAnimal>(xml);
Animal myAnimal = AnimalSerializer.CreateFromSerialized(deserialized);
Just to reiterate, the SerializableAnimal class and usage is ONLY used in the final layer(s) of your application that need to serialize/deserialize. Everything else works against your immutable Animal classes.
EDITx2: Another major benefit of this managed separation is you can deal with legacy changes in your code. For example, you have a Fish type, which is pretty broad. Maybe you split it into Shark and Goldfish later and decide all your old Fish type should be considered Goldfish. With this separation of serialization, you can now place a check for any old Fish and convert them to Goldfish whereas direct serialization would result in an exception because Fish no longer exists.
I would implement it with subclasses, but where the instances of the subclasses don't store any data, like this:
public abstract class AnimalBase {
public abstract string Name { get; } // user-readable
public abstract double Weight { get; }
public abstract Habitat Habitat { get; }
public void Swim(); { /* swim implementation; the same for all animals but uses the value of Weight */ }
// ensure that two instances of the same type are equal
public override bool Equals(object o)
{
return o != null && o.GetType() == this.GetType();
}
public override int GetHashCode()
{
return this.GetType().GetHashCode();
}
}
// subclasses store no data; they differ only in what their properties return
public class Otter : AnimalBase
{
public override string Name { return "Otter"; }
public override double Weight { return 10; }
// here we use a private static member to hold an instance of a class
// that we only want to create once
private static readonly Habitat habitat = new Habitat("North America");
public override Habitat Habitat { return habitat; }
}
Now it shouldn't matter that you have multiple "instances", because each instance only contains its type information (no actual data). Overriding Equals and GetHashCode on the base class means that different instances of the same class will be considered equal.
The way I see it, you are looking for the right creational pattern to suit your needs.
Your first option is similar to factory method.
The second one looks like a type hierarchy with an optional abstract factory.
The third one is a singleton.
It seems like your only problem is serialization. What kind of serialization we're talking about: binary or XML? If it's binary, have you looked at custom serialization? If it's XML, you should either stick with the second option, also use custom serialization or delegate the serialization logic outside of your classes.
I personally think the latter is the most architecturally sound solution. Mixing object creation and serialization is a bad idea.
I'd go with the third option (objects!), but with a little twist.
The point is: You have a set of objects with some particular schema...
public class Animal {
public string Name { get; set; } // user-readable
public double Weight { get; set; }
public Habitat Habitat { get; set; }
public void Swim();
}
but you want them to be predefined. The catch is: If you serialize such object, you don't want to have its fields serialized. Initializing the fields is the responsibility of application, and the only thing you want to actually have in your serialized version is the "type" of the animal. This will allow you to change "Otter" to "Sea Otter" and keep the data consistent.
Hence, you'd need some representation of the "animal type" - and that's the only thing you want to have serialized. On deserialization, you want to read the type identifier and initialize all the fields based on it.
Oh, and another catch - upon deserialization, you don't want to create a new object! You want to read the ID (and the ID only) and retrieve one of the predefined objects (that corresponds to this ID).
The code could look like:
public class Animal {
public static Animal Otter;
public static Animal Narwhal;
// returns one of the static objects
public static Animal GetAnimalById(int id) {...}
// this is here only for serialization,
// also it's the only thing that needs to be serialized
public int ID { get; set; }
public string Name { get; set; }
public double Weight { get; set; }
public Habitat Habitat { get; set; }
public void Swim();
}
So far, so good. If there are dependencies that prohibit you from making instances static, you could throw in some lazy initialization for all the Animal objects.
The Animal class starts to kind of look like "a couple singletons in one place".
Now how to hook it into .NET's serialization mechanism (BinarySerializer or DataContractSerializer). We want the serializer to use GetAnimalById instead of the constructor when deserializing, and only store ID when serializing.
Depending on your serialization API, you can do this with ISerializationSurrogate or IDataContractSurrogate. This is an example:
class Surrogate : IDataContractSurrogate {
public Type GetDataContractType(Type type) {
if (typeof(Animal).IsAssignableFrom(type)) return typeof(int);
return type;
}
public object GetObjectToSerialize(object obj, Type targetType) {
// map any animal to its ID
if (obj is Animal) return ((Animal)obj).ID;
return obj;
}
public object GetDeserializedObject(object obj, Type targetType) {
// use the static accessor instead of a constructor!
if (targetType == typeof(Animal)) return Animal.GetAnimalById((int)obj);
}
}
BTW: DataContacts seem to have a bug (or is it a feature?) which causes them to act weirdly when the substitute type is a basic type. I've had such problem when serializing objeects as strings - the GetDeserializedObject method was never fired when deserializing them. If you run into this behaviour, use a wrapper class or struct around that single int field in the surrogate.
I have inherited the following (terrible) code and am wondering how best to refactor it.
There are large if/else clauses all over the codebase, one of which is similar to below :
public class BaseResultItem
{
public int Property1 { get; set; }
}
public class ResultItem1 : BaseResultItem
{
public int Property2 { get; set; }
}
public class ResultItem2 : BaseResultItem
{
public int Property3 { get; set; }
}
public class BaseHistoryItem
{
public int Property1 { get; set; }
}
public class HistoryItem1 : BaseHistoryItem
{
public int Property2 { get; set; }
}
public class HistoryItem2 : BaseHistoryItem
{
public int Property3 { get; set; }
}
public class HistoryBuilder
{
public BaseHistoryItem BuildHistory(BaseResultItem result)
{
BaseHistoryItem history = new BaseHistoryItem
{
Property1 = result.Property1
};
if (result is ResultItem1)
{
((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}
else if (result is ResultItem2)
{
((HistoryItem2)history).Property3 = ((ResultItem2)result).Property3;
}
return history;
}
}
Note that this is a simplified example and there are many more classes involved in the actual code. There are similar if/else clauses all over the place.
I have been looking at the abstract factory pattern but I am having some problems.
Basically I am assuming that to avoid the if/else problems I need to pass the actual dervied types around. So BuildHistory should not use base types and maybe there should be multiple methods, one per derived type?
If you can't change the DTO classes perhaps you can try to subclass HistoryBuilder to deal with the different subclasses. Then you use the appropriate HistoryBuilderX to create a HistoryItem from a ResultItem. Then the question is how to get the appropriate HistoryBuilderX for the ResultItem supplied.
Still, if you can't change the BaseResultItem class to include a GetBuilder function you need to use some if..else if.. construct that inspects the classtypes of your ResultItems.
Or you create a Registry where every ResultItem class is registered with its corresponding HistoryBuilderX class. But that might be overkill.
The general 'design pattern' is simply to use object orientation with polymorphism instead of type checks. Thus: a BuildHistory method inside BaseResultItem, overridden by descendants.
Any code which checks the concrete type of an object smells (in a refactoring sense). Supporting different behaviours for different types is what OO is about.
Use polymorphism to remove the type checks.
if (result is ResultItem1)
{
((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}
Becomes then something like
result.addToHistory( history );
If for some reason, you don't want to scatter the logic in the item classes, have a look at the visitor pattern. In this case, you have something like:
public class Visitor {
History history;
public visit ( ResultItem1 item ) { ... }
public visit ( ResultItem2 item ) { ... }
...
}
public class ResultItem1 {
public accept( Visitor v ) { v.visit( this ); }
}
The typecheck is removed by the double-dispatch in the visitor, which is slightly more elegant.
I didn't understood exactly how the various kind of history relates to the various kind of items. So this is just a sketch of possibles direction to follow.