I am writing code that has a super class that encapsulates an object that is specific the every certain subclass for example below are example relationships for the type of subclass with the type of class it encapsulates. All the encapsulating classes also have implicit casts to the classes they encapsulate. (The non abstract ones).
Item => Model.Item
Box => Model.Box
Rather than using the non type safe object type I felt that I could use generics to gain type safety and elegance.
public abstract class Entity<T> where T: class
{
protected T DataObject;
}
public class Item : Entity<Model.Item>
{
// Can use this.DataObject and it is type Model.Item
}
public class Box : Entity<Model.Box>
{
// Can use this.DataObject and it is type Model.Box
}
This approach worked fine until I wanted to start making second level subclasses so I changed the definition of Item to (note Model.AItem extends Model.Item)
public class Item<T> : Entity<T> where T : Model.Item
{
// Can use this.DataObject and it is type Model.Item
}
public class AItem : Item<Model.AItem>
{
// Can use this.DataObject and it is type Model.AItem
}
This has two main problems for me, one when I want to reference a second level object as the abstract class I have to put in that Item<Model.Item> I want there to be a way for this to be implicit as there is never a case where that is not true. Also it wreaks havoc on my implicit casting with abstract classes as they can’t be instantiated.
Nothing doesn’t work, I basically thing I want to remove the genetic parameters while still keeping the ability to have a specifically typed encapulated object. The encapsulated object is really a Linq to SQL object and the surrounding object is forming a sort of buffer for changes along with implementing other functionality and providing a more direct representation of the data as it is in the application. I need to keep the LinqToSql entity so that way I have a way of still using LinqToSql to update changes and manage inserts/deletes without reinventing the wheel. I was using partial classes to do this but there was too much of a mix up with objects belonging to different datacontexts.
EDIT: Full story
I have a survey assessment that is made up of different types of Survey Objects. Some survey objects such as the actually question objects are made up of different other objects. For example a block is a survey object which has a itembank, the item bank is made up of items which can be many different types(currently represented as subclasses). I have so far been using the Linq to SQL enties directly as my model with some changes made via partial classes. Item’s has a script that executes before and after the item is called up in the survey. This script can change certain properties of the item but since my linq classes are my model whenever I make a change to them by the nature of linq it wants to persist those changes to the database.
Does anyone see a better way to do things?
See this about covariance and contravariance. You might be able to make an
interface IEntity<out T> where T : class { T DataObject { get; } }, and make your abstract class implement this, then you can do this sort of conversion implicitly:If you can’t do this using a covariant interface, then you can’t really logically do what you’re trying to do, and you should try to figure out a solution from some other angle.