How to represent different entities that have identical behavior? - c#

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.

Related

How to call a method of a class embedding List<X> and List<Y>, and of Y, from the X elements themselves?

I though I would easily find an answer to this question but I couldn't find yet.
Let's say I have the following classes :
public class Universe
{
public list<Human> Humans { get; set; }
public list<Animal> Animals { get; set; }
public God AlphaOmega { get; set; }
public void UniverseAction()
{
//dosmthg
}
public Animal FindAnAnimal()
{
//find an animal
}
}
public class Animal
{
//many Animal things
public void AnimalyStuff()
{
//DoSmthg
}
}
public class God
{
public bool CantTouchThis = true;
}
public class Human
{
//many Human things
public void CallingUniverseAction()
{
//How to?
}
public void CallingAnimalyStuff()
{
}
}
Note that those names are purely given as examples, I could have used A, B, C & D.
So I want that all humans be able to call UniverseAction() so from a specific Human I can use it.
I also want that humans be able to call AnimalyStuff() so a specific Human would need to access the FindAnAnimal in Universe to retrieve a specific Animal and do the AnimalyStuff()
For a while when dealing with this kind of requirement I used to pass Universe in the constructor of Human. Though I don't want that Human can expose all method / parameters of Universe. For instance, Human should not interract with AlphaOmega
What would be the most appropriate way to do it?
Is it through an action delegate that I'll pass in the constructor? If so how, I never used action delegates. Also will I not end up with passing many delegates if I want Human to access many methods?
You have a couple options available to you if you want to limit the available information to Human.
If you are okay with only hiding the information, where it is still there, but not accessible unless you explicitly un-hide it consider using a Interface to limit the available members.
If you are okay with the Universe being passed around, but certain members being inaccessible to Human, consider using the protected modifier to limit access to members that inherit from the Universe class.
If you are okay with passing things in the constructor(like you recommended) you could pass any number of methods(delegates) to the human class so they can get the information any time they need, but it involves more complex implementation(I already did most of the work for you below)
If you're not sure what you want to do, and this doesn't need(for some specific business requirement) to work in the way you have described - Consider researching general Object Oriented Programing design patterns. There's a ton of resources online that can teach you OOP. The main topic I would recommend is the SOLID principles which will teach you a lot and be really useful. Thanks #flydog57 for mentioning this, as this would be more useful in the long run.
Interfaces
To visually hide/abstract the information unless explicitly accessed(casted) you can implement an IUniverse interface that defines only the members that you want publicly accessible.
// these would be the only accessible members
public interface IUniverse
{
Animal FindAnAnimal();
void UniverseAction();
}
public class Universe : IUniverse { ... }
public class Human
{
private readonly IUniverse universe;
public Human(IUniverse universe)
{
this.universe = universe;
}
}
Using interfaces to abstract which information should be available where can be really powerful! However, this does not prevent Human from casting the IUniverse to a Universe object explicitly and access it's other public members.
Protected Modifier
You can use the protected modifier (and a couple other ones) to completely remove access to information to other classes that don't meet certain requirements. For example the protected modifier would prohibit access to any protected members from any class that does not inherit from Universe. Make sure to checkout Access Modifiers for more information about the other options available to you.
public class Universe
{
protected List<Human> Humans { get; set; } = new();
protected List<Animal> Animals { get; set; } = new();
protected God AlphaOmega { get; set; }
public void UniverseAction()
{
//dosmthg
Console.WriteLine(nameof(UniverseAction));
}
public Animal FindAnAnimal()
{
//find an animal
Console.WriteLine(nameof(FindAnAnimal));
return Animals.FirstOrDefault();
}
}
public class Human
{
private readonly Universe universe;
public Human(Universe universe)
{
this.universe = universe;
}
//many Human things
public void CallingUniverseAction()
{
//How to?
universe.UniverseAction(); // works
UniverseAction.Humans.Clear(); // no access it's protected
}
public void CallingAnimalyStuff()
{
var animal = universe.FindAnAnimal(); // works
UniverseAction.Animals.Clear(); // no access it's protected
AlphaOmega.Kill(); // no access it's protected
}
}
Passing Delegates
You could for example pass delegates to the human to avoid passing around the Universe instance it self. Any method group is usually convertible to some form of Action or Func. Make sure to checkout Actions and Funcs for more information on both and how they can be passed around.
You can pass these around super simply for example:
public class Universe
{
public Human CreateHuman()
{
var newHuman = new Human(UniverseAction, FindAnAnimal);
Humans.Add(newHuman);
return newHuman;
}
}
public class Human
{
private readonly Action universeAction;
private readonly Func<Animal> animalyStuff;
public Human(Action universeAction, Func<Animal> animalyStuff)
{
this.universeAction= universeAction;
this.animalyStuff = animalyStuff;
}
//many Human things
public void CallingUniverseAction()
{
//How to?
universeAction?.Invoke();
}
public void CallingAnimalyStuff()
{
var animal = animalyStuff?.Invoke();
}
}
You could also implement a more robust, but more complex system if you need to pass a large amount of functions in the constructor like 20+. Passing a large number of things in a constructor is not a viable pattern, but it could work if you really wanted to, if you are required to do it to interop with legacy systems.
Here's a short snippet of what an implementation of that using reflection might look like.
public class Universe
{
protected List<Human> Humans { get; set; } = new();
protected List<Animal> Animals { get; set; } = new();
protected God AlphaOmega { get; set; }
public Human CreateHuman()
{
var newHuman = new Human(
(nameof(FindAnAnimal), (Func<Animal>)FindAnAnimal),
(nameof(UniverseAction), (Action)UniverseAction)
);
Humans.Add(newHuman);
return newHuman;
}
public void UniverseAction()
{
//dosmthg
}
public Animal FindAnAnimal()
{
//find an animal
}
}
public class Human
{
//many Human things
public void CallingUniverseAction()
{
Invoke(nameof(Universe.UniverseAction));
}
public void CallingAnimalyStuff()
{
var animal = Invoke(nameof(Universe.FindAnAnimal));
}
public Human(params (string Name, object Delegate)[] Methods)
{
foreach (var item in Methods)
{
InvokableReferences.Add(item.Name, item.Delegate);
}
}
private Dictionary<string, object> InvokableReferences = new();
public object Invoke(string DelegateName, params object[] Parameters)
{
if (InvokableReferences.ContainsKey(DelegateName))
{
object storedDelegate = InvokableReferences[DelegateName];
var delegateType = storedDelegate.GetType();
// check for the invoke method
var invokeMethod = delegateType.GetMethod(nameof(Invoke));
if (invokeMethod != null)
{
// check to see if it's an action or a func
var methodParams = invokeMethod.GetParameters();
if (methodParams is null)
{
// since there were no parameters then it is probably an Action or Func<T>
return invokeMethod.Invoke(storedDelegate, null);
}
// if it requires parameters it's probably a Action<T,..N> or Func<T...N,TResult>
// make sure we have enough parameters to invoke the method
if (methodParams.Length == Parameters.Length)
{
return invokeMethod.Invoke(storedDelegate, Parameters);
}
}
}
// if we failed to find the item return null;
return default;
}
}

Base Class Enum Implemented Differently in Derived Classes

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";
}

Inheritance and Liskov substitution principle

I am struggling to adhere to Liskov substitution principle when creating my class structure. I want to have a Collection of calendar items stored within a Day class. There need to be several different type of CalendarItems e.g:
AppointmentItem
NoteItem
RotaItem
they all share some common functionality which is presnt in the abstract base class CalendarItem:
public abstract class CalendarBaseItem
{
public string Description { get; private set; }
public List<string> Notes { get; private set; }
public TimeSpan StartTime { get; private set; }
public TimeSpan EndTime { get; private set; }
public int ID { get; private set; }
public DateTime date { get; private set; }
code omitted...
}
but then for example RotaItem has some extra functionality:
public class RotaItem : CalendarBaseItem
{
public string RotaName { get; private set; }
private bool spansTwoDays;
public bool spanTwoDays()
{
return this.spansTwoDays;
}
}
the other classes also add there own logic etc.
I have a collection of CalendarBaseItem for my day class:
List<CalendarBaseItem> calendarItems;
but on reviewing this I can see that I am breaking LSP principles as I have to check and cast each concrete type to get at the functionality that I desire for each subclass.
I would be grateful if someone could advise how to avoid this problem. Should I use a composition approach and add a CalendarItem class to each of the final classes e.g
public class RotaItem
{
private CalendarBaseItem baseItem;
public string RotaName { get; private set; }
private bool spansTwoDays;
public RotaItem(baseArgs,rotaArgs)
{
baseItem = new CalendarBaseItem(baseArgs);
}
public bool spanTwoDays()
{
return this.spansTwoDays;
}
}
The only problem here is that I will then need a seperate collection for each Concrete CalendarItem in my Day class?
I think what you're encountering is not so much a Liskov Substitution Principle violation as you are encountering a polymorphism limitation in most languages.
With something like List<CalendarBaseItem> the compiler is inferring that you're only dealing with CalendarBaseItem which obviously can't be true if CalendarBaseItem is abstract--but that's what a strongly-typed language does: It's only been told about CalendarBaseItem so that's what it limits usage to.
There are patterns that allow you to deal with this sort of limitation. The most popular is the double-dispatch pattern: a specialization of multiple dispatch that dispatches method calls to the run-time type. This can be accomplished by providing an override, that when dispatched, dispatches the intended method. (i.e. "double dispatch"). It's hard to associate exactly to your circumstances because of the lack of detail. But, if you wanted to do some processing based on some sort of other type for example:
public abstract class CalendarBaseItem
{
abstract void Process(SomeData somedata);
//...
}
public class RotaItem : CalendarBaseItem
{
public override void Process(SomeData somedata)
{
// now we know we're dealing with a `RotaItem` instance,
// and the specialized ProcessItem can be called
someData.ProcessItem(this);
}
//...
}
public class SomeData
{
public void ProcessItem(RotaItem item)
{
//...
}
public void ProcessItem(NoteItem item)
{
//...
}
}
which would replace something like:
var someData = new SomeData();
foreach(var item in calendarItems)
someData.ProcessItem(item);
Now, that's the "classical" way of doing in in C#--which spans all versions of C#. With C# 4 the dynamic keyword was introduced to allow run-time type evaluation. So, you could do what you want without having to write the double-dispatch yourself simply by casting your item to dynamic. Which forces the method evaluation to occur at run-time and thus will chose the specialized override:
var someData = new SomeData();
foreach(var item in calendarItems)
someData.ProcessItem((dynamic)item);
This introduces potential run-time exceptions that you'd likely want to catch and deal with--which is why some people don't like this so much. It's also currently very slow in comparison, so it's not recommended in tight loops that are performance sensitive.

Have a wrapper object expose its wrapee's properties

I'm currently trying to figure out how to have a wrapper class expose the properties of whatever it is wrapping without having to manually set them one by one in the wrapper class. I've been trying to figure out if this is even a good design choice or if I'm totally misguided and going off into a very bad placeā„¢ by doing this.
I also already have my wrapper class inheriting something...
Example code below (fake objects so don't read into them please):
public class Car {
public String Name { get; set; }
public String Status { get; set; }
public String Type { get; set; }
public Car(takes params) {
// makes car!
}
}
public class CarWrapper : OtherAutomotiveRelatedThing {
public Car car;
public CarWrapper(Car c) {
car = c;
}
}
public class OtherAutomotiveRelatedThing {
public String Property1 { get; protected set; }
public String Property2 { get; protected set; }
}
I'm using inheritance on the wrapper object because I can not modify the base Car class and it needs the properties of other automotive thing. Multiple other classes inherit from OtherAutomotiveRelatedThing as well.
I return a list of the CarWrapper objects as Json (because I'm building a web app) and the wrapper object is causing problems for me. When cast/converted to Json the CarWrapper objects in the list all contain another nested object - the Car object and the framework I'm using can't get at its properties to do what it needs.
Is there a way to expose the wrapped Car object's properties at the "top level" of the CarWrapper without doing the following:
public class CarWrapper : OtherAutomotiveRelatedThing {
public Car car;
public String Name { get; private set; }
public String Status { get; private set; }
public String Type { get; private set; }
public CarWrapper(Car c) {
car = c;
this.Name = c.Name;
this.Status = c.Status;
this.Type = c.Type;
}
}
Please let me know if I'm not being clear, if you have any questions, or need/want more info.
Thanks!
For me it looks like you want prototype-style programming like in JavaScript, which is not they use in OOP.
Maybe it's good start to think of it as "If I have two different car wrappers (with differnt properties set), how should I pass any of them a method?" or "Can I have a single wrapper which wraps Car and Animal", and "How to expose public property which has the same name but different meaning for Car and Animal, like skin color?" etc
Answers may help you identify if you need say interfaces, or wrappers which expose public objects, or pure encapsulation, or changing language to say JavaScript.

Creating read-only versions of classes in a complex object structure

In my current project I need to be able to have both editable and read-only versions of classes. So that when the classes are displayed in a List or PropertGrid the user is not able to edit objects they should not be allowed to.
To do this I'm following the design pattern shown in the diagram below. I start with a read-only interface (IWidget), and then create an edtiable class which implements this interface (Widget). Next I create a read-only class (ReadOnlyWidget) which simply wraps the mutable class and also implements the read only interface.
I'm following this pattern for a number of different unrelated types. But now I want to add a search function to my program, which can generate results that include any variety of types including both mutable and immutable versions. So now I want to add another set of interfaces (IItem, IMutableItem) that define properties which apply to all types. So IItem defines a set of generic immutable properties, and IMutableItem defines the same properties but editable. In the end a search will return a collection of IItems, which can then later be cast to more specific types if needed.
Yet, I'm not sure if I'm setting up the relationships to IMutable and IItem correctly. Right now I have each of the interfaces (IWidget, IDooHickey) inheriting from IItem, and then the mutable classes (Widget, DooHickey) in addition also implement IMutableItem.
Alternatively, I was also thinking I could then set IMutableItem to inherit from IItem, which would hide its read-only properties with new properties that have both get and set accessors. Then the mutable classes would implement IMutableItem, and the read-only classes would implement IItem.
I'd appreciate any suggestions or criticisms regarding any of this.
Class Diagram
Code
public interface IItem
{
string ItemName { get; }
}
public interface IMutableItem
{
string ItemName { get; set; }
}
public interface IWidget:IItem
{
void Wiggle();
}
public abstract class Widget : IWidget, IMutableItem
{
public string ItemName
{
get;
set;
}
public void Wiggle()
{
//wiggle a little
}
}
public class ReadOnlyWidget : IWidget
{
private Widget _widget;
public ReadOnlyWidget(Widget widget)
{
this._widget = widget;
}
public void Wiggle()
{
_widget.Wiggle();
}
public string ItemName
{
get {return _widget.ItemName; }
}
}
public interface IDoohickey:IItem
{
void DoSomthing();
}
public abstract class Doohickey : IDoohickey, IMutableItem
{
public void DoSomthing()
{
//work it, work it
}
public string ItemName
{
get;
set;
}
}
public class ReadOnlyDoohickey : IDoohickey
{
private Doohickey _doohicky;
public ReadOnlyDoohickey(Doohickey doohicky)
{
this._doohicky = doohicky;
}
public string ItemName
{
get { return _doohicky.ItemName; }
}
public void DoSomthing()
{
this._doohicky.DoSomthing();
}
}
Is it OK to create another object when you need a readonly copy? If so then you can use the technique in the included code. If not, I think a wrapper is probably your best bet when it comes to this.
internal class Test
{
private int _id;
public virtual int ID
{
get
{
return _id;
}
set
{
if (ReadOnly)
{
throw new InvalidOperationException("Cannot set properties on a readonly instance.");
}
}
}
private string _name;
public virtual string Name
{
get
{
return _name;
}
set
{
if (ReadOnly)
{
throw new InvalidOperationException("Cannot set properties on a readonly instance.");
}
}
}
public bool ReadOnly { get; private set; }
public Test(int id = -1, string name = null)
: this(id, name, false)
{ }
private Test(int id, string name, bool readOnly)
{
ID = id;
Name = name;
ReadOnly = readOnly;
}
public Test AsReadOnly()
{
return new Test(ID, Name, true);
}
}
I would suggest that for each main class or interface, there be three defined classes: a "readable" class, a "changeable" class, and an "immutable" class. Only the "changeable" or "immutable" classes should exist as concrete types; they should both derive from an abstract "readable" class. Code which wants to store an object secure in the knowledge that it never changes should store the "immutable" class; code that wants to edit an object should use the "changeable" class. Code which isn't going to write to something but doesn't care if it holds the same value forever can accept objects of the "readable" base type.
The readable version should include public abstract methods AsChangeable(), AsImmutable(), public virtual method AsNewChangeable(), and protected virtual method AsNewImmutable(). The "changeable" classes should define AsChangeable() to return this, and AsImmutable to return AsNewImmutable(). The "immutable" classes should define AsChangeable() to return AsNewChangeable() and AsImmutable() to return this.
The biggest difficulty with all this is that inheritance doesn't work terribly well if one tries to use class types rather than interfaces. For example, if one would like to have an EnhancedCustomer class which inherits from BasicCustomer, then ImmutableEnhancedCustomer should inherit from both ImmutableBasicCustomer and ReadableEnhancedCustomer, but .net doesn't allow such dual inheritance. One could use an interface IImmutableEnhancedCustomer rather than a class, but some people would consider an 'immutable interace' to be a bit of a smell since there's no way a module that defines an interface in such a way that outsiders can use it without also allowing outsiders to define their own implementations.
Abandon hope all ye who enter here!!!
I suspect that in the long run your code is going to be very confusing. Your class diagram suggests that all properties are editable (or not) in a given object. Or are your (I'm)mutable interfaces introducing new properties that are all immutable or not, separate from the "core"/inheriting class?
Either way I think you're going to end up with playing games with property name variations and/or hiding inherited properties
Marker Interfaces Perhaps?
Consider making all properties in your classes mutable. Then implement IMutable (I don't like the name IItem) and IImutable as a marker interfaces. That is, there is literally nothing defined in the interface body. But it allows client code to handle the objects as a IImutable reference, for example.
This implies that either (a) your client code plays nice and respects it's mutability, or (b) all your objects are wrapped by a "controller" class that enforces the given object's mutability.
Could be too late :-), but the cause "The keyword 'new' is required on property because it hides property ..." is a bug in Resharper, no problem with the compiler. See the example below:
public interface IEntityReadOnly
{
int Prop { get; }
}
public interface IEntity : IEntityReadOnly
{
int Prop { set; }
}
public class Entity : IEntity
{
public int Prop { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var entity = new Entity();
(entity as IEntity).Prop = 2;
Assert.AreEqual(2, (entity as IEntityReadOnly).Prop);
}
}
Same for the case without interfaces. The only limitation, you can't use auto-properties
public class User
{
public User(string userName)
{
this.userName = userName;
}
protected string userName;
public string UserName { get { return userName; } }
}
public class UserUpdatable : User
{
public UserUpdatable()
: base(null)
{
}
public string UserName { set { userName = value; } }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var user = new UserUpdatable {UserName = "George"};
Assert.AreEqual("George", (user as User).UserName);
}
}

Categories