tags:

views:

81

answers:

6

I have a problem and not so sure how to solve it..

Consider the class:

public class BaseClass<T>
{

    public T PreviousInstance { get; set; }

}

Now my secondary data class:

public class DataClass : BaseClass<DataClass>
{
    public bool ABoolProperty { get; set; }
}

So i have DataClass (which is populated through a LINQ To WMI bridge on when a WMI object changes) when populated from a change event provides the changed data and the previous data before the edit which works great. I now have a third class:

public class DerivedDataClass : DataClass
{
    public string AStringProperty { get; set; }
}

My problem is that DerviedDataClass.PreviousInstance is still of type DataClass, which means i wont get any properties for PreviousInstance that are declared in DerivedDataClass.

I have thought about declaring DataClass ie

public class DataClass<T> : BaseClass<T>

Which would allow the properties from DerivedDataClass to be available in PreviousInstance. However i still need to be able to use DataClass on its own without having to declare it like:

DataClass<DataClass<object>>

just to get it to work what i would really like is to have a generic version of the class and a non generic version, with out having to declare 2 seperate classes with the same properties.

So any ideas? :)

A: 

Hey,

You could try shadowing the property as in the following:

public class DerivedDataClass : DataClass
{
  new public DerivedDataClass PreviousInstance
  {
     get { return (DerivedDataClass)base.PreviousInstance; }
     set { base.PreviousInstance = value; }
  }
}

If PreviousInstance is not of the correct type, you will get an error. Note: you can't refer to an instance of DerivedDataClass as its base type DataClass, because then it will use the DataClass version of PreviousInstance, and circumvent the shadowing.

Brian
A: 

Well what you want is not possible basically because multiple inheritance is not allowed.

What you can do is carrying over the generic type parameter from the base class, as in

public class DataClass<T> : BaseClass<T>

Depending on what you want to achieve, this could do the trick for you. Remember that generics are not intended to be used like template text for source code.

herzmeister der welten
A: 

At the moment the only way I can see is to introduce another layer in the chain:

public abstract class AbstractDataClass<T> : BaseClass<T>
{ 
   public bool ABoolProperty { get; set; }
}

public class DataClass : AbstractDataClass<DataClass>
{
}

public class DerivedClass : AbstractDataClass<DerivedClass>
{
   public string AStringProperty { get; set; }
}

Though I admit it is very clunky especially when you start getting into increasing levels of the hierarchy

Ian Johnson
+2  A: 

You could take the following approach:-

public interface IPreviousInstance<T>
{
    T PreviousInstance { get; set; }
}

public class DataClass : IPreviousInstance<DataClass>
{
    public DataClass PreviousInstance { get; set; }
    public bool ABoolProperty { get; set; }
}

public class DerivedDataClass : DataClass, IPreviousInstance<DerivedDataClass>
{
    public new DerivedDataClass PreviousInstance { get; set; }
    public string AStringProperty { get; set; }
}
AdamRalph
I don't think abstract properties (as PreviousInstance in your example) can be implemented as automatic properties.Still +1 because I think your approach is the best.
ShdNx
It's not an abstract property, it's an interface property. I've checked and the code does compile.
AdamRalph
Thanks Adam, i did consider this type of solution but my library is to be used by my team and if they derive there own data they would have to *know* to implement the interface, when what i need is an automatic way of changing the type of PreviousInstance.
Gavin Uttley
hi Gavin, although they would need to know to implement the interface, would they not also have to know to implement the abstract class?
AdamRalph
+2  A: 

Inheritance hierarchies are there to model the notion of "I can use an instance of a derived class anywhere that an instance of a base class is required", right? If you have a method that takes a Fruit then you can pass it an Apple and know there will be no problems.

Let's simplify your code. You have

class B<T>
{
    public T Another { get; set; }
}
class Fruit : B<Fruit> {}
class Apple : Fruit {}
class Orange : Fruit {}

Now, Apple.Another is of type Fruit, not of type Apple. It has to be of type Fruit, because you could have a method

void AddAnOrange(Fruit f)
{
    f.Another = new Orange();
}

This has to work even if you pass in an Apple -- the contract of Fruit is that a Fruit refers to any other Fruit, not "a fruit refers to another fruit of some more derived type that is not known until runtime".

If you need to model the relationship "An apple refers to another apple, an orange refers to another orange", then don't do it by saying "A fruit refers to another fruit"; that's not capturing the thing you want to model correctly, and will just cause you pain later.

Eric Lippert
A: 

Thanks for the response guys, but non of the solutions quite meet what i need. The library i am making is to be used by my team and if they need to derive their own data then it needs to be automatic so they dont have to have indepth knowledge of having to implement interfaces or shadow a property.

What i have decided to do is add another class decleration so that the end developer can use the generic (for derived classes) or non generic for straight use in their application.

for example:

public class DataClass<T> : BaseClass<T>
{
    public bool ABoolProperty { get; set; }
}

public class DataClass : DataClass<DataClass>  
{
}
Gavin Uttley