jsuddsjr
jsuddsjr

Reputation: 551

.Net generics -- implementation inheritance from interface

I have two sequences of objects 'A' and 'B'. Comparing the sequences should produce a third sequence 'C' of elements that indicate whether:

All remaining elements are considered as "matched".

What I would like to do:

Declare Inserted<T>, Deleted<T>, and Matched<T> generic classes that inherit all their properties from the T base class. The generic class must be able to instantiate itself from the object it inherits.

The code:

public interface IInstantiable<T>
{
    void CopyFrom(T o);
}

[Serializable]
public class Inserted<T> : T
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        this.CopyFrom(t);
    }
}

The error:

'MyNamespace.Inserted<T>' does not contain a definition for 'CopyFrom' and no 
extension method 'CopyFrom' accepting a first argument of type 'MyNamespace.Inserted<T>' 
could be found (are you missing a using directive or an assembly reference?)

Further discussion:

I define my own IInstantiable interface to enforce the existence of a CopyFrom method. I cannot use the standard ICloneable interface, because it only defines a method that copies the object to a new instance, whereas I need the object to copy its members in the constructor.

The error goes away if the generic defines its own implementation of the CopyFrom method; however, this does not achieve the desired goal of specializing the CopyFrom method to handle the specific needs of the base class. Only the base class could know what properties should be copied. (Or am I missing something?)

Note: The final object should have the same public members as its base class, as the object should be capable of serialization.

Is this possible in .NET?

The answer:

What I am attempting to do is impossible, simply because the generic class cannot be an extension of the template base class. Visual Studio complains "Cannot derive from 'T' because it is a type parameter." (I hadn't noticed this error yet because I had not implemented the CopyFrom method in the generic class yet.)

If I were to change the interface into a class and supply a stub implementation in that class, I could inherit from it as suggested below; however, this introduces a new base class into my inheritance hierarchy.

public class IInstantiable<T>
{
    public virtual void CopyFrom(T o) { }
}

[Serializable]
public class Inserted<T> : IInstantiable<T>
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        base.CopyFrom(t);
    }
}

Unfortunately, I cannot use this new base class in its templatized form because I must introduce it at the root of my inheritance hierarchy. It works only if I remove the template and make it as generic as possible.

public class IInstantiable
{
    public virtual void CopyFrom(Object o) { }
}

However, this still does not make my Inserted<T> generic look like the object it is initialized from, and since I cannot inherit from the same type as the type parameter, it does not suit my initial purpose.

Moving away from "fancy generics" based on the type system to more (ahem) generic annotated structures might prove to be the best solution; however, the default behavior of my selected serialization approach (XmlSerialization) does not have the automatic support that would make this configuration a viable solution. Generics will not work; use hard-coded class definitions instead.

Upvotes: 3

Views: 477

Answers (2)

Eamon Nerbonne
Eamon Nerbonne

Reputation: 48066

If I understand correctly, you want to annotate a sequence of objects with the notion of what their state is (inserted, deleted, or matched).

You don't really need fancy generics for this; what's wrong with:

enum ChangeState { Inserted, Deleted, Matched }
struct<T> Annotated { 
    public T Obj; 
    public ChangeState;
}

You can mark this for serialization however you want (the Annotated object can serialize just fine without the same properties/fields).

Though you can encode more information in the type system, it's unclear to me what the benefit would be here. Are you sure you want to do that?

Upvotes: 1

Travis Parks
Travis Parks

Reputation: 8695

This is indirectly what you're trying to declare in your code above.

[Serializable]
public class Inserted<T> : IInstantiable<T>
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        this.CopyFrom(t);
    }
}

Does this make sense?

.NET doesn't allow you to inherit from a generic parameter. How could it? Generics are evaluated at runtime but it needs to know what type your class is at compile time.

Upvotes: 3

Related Questions