3

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

  • the objects were "deleted" from 'A' or
  • "inserted" from 'B'.

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.

3
  • 3
    Firstly Inserted<T> : T isn't allowed. Commented Feb 28, 2013 at 21:53
  • 2
    It looks like you just want: public class Inserted<T> : IInstantiable<T>. Does that not work for you? Commented Feb 28, 2013 at 21:54
  • 2
    Well I did notice that you didn't inherit from IInstantiable<T>, you just created a templated type based on it. Have you tried public class Inserted<T> : IInstantiable<T> : where T IInstantiable<T>? (actually since you didn't template the where wouldn't compile so leave that off) Commented Feb 28, 2013 at 21:55

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

The generic constraint shouldn't be required at all.
Inheriting from a generic parameter is definitely not possible. But I don't think this is some fundamental problem. Why would the compiler need to know "the" type at compile time? It doesn't for generics in any case. It doesn't even know the memory layout (e.g. value-typed parameters; say a tuple of long and byte). C# just doesn't happen to support it.
Unfortunately, this answer doesn't provide a solution to what I'm trying to accomplish. See Answer section above. @Eamon, there's a lot of things that C# just doesn't happen to support. <sigh>
1

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?

4 Comments

This is an intriguing solution. It does complicate things somewhat because I would be using XmlSerialization to create new markup elements that would depend on the state of the flag. The element contents would need to be the same as the original objects, although I can probably work around that.
Ah, that helps: I was having difficulty getting at the underlying aim you had :-). You could use IXmlSerializable to ensure the serialization is "additive"; i.e. generates the same xml as the object it contains just with some extra attribute.
Yes, the XmlArrayItem attribute allows me to easily change the element name based on the object type. I don't see such an easy way to do the same based on a object property value. I have thus far been able to avoid a custom implementation of IXmlSerializable -- and I was hoping to keep it that way. Thanks!
Yeah, and by the look of it, IXmlSerializable wouldn't actually work - it can control the contents of the element it is serialized as, but not the name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.