views:

44

answers:

1

I have this abstract class and concrete implementation (they are in different assemblies):

public abstract class MyAbstractClass
{
    private static readonly int MyAbstractClassVersion = 1;
    public abstract int ImplementedVersion  { get; }

    protected MyAbstractClass()
    {
        CheckVersion();
    }

    private void CheckVersion()
    {
        var message =
            string.Format(
            "MyAbstractClass implements Version {0}, concrete is Version {1}",
            RepositoryVersion, ImplementedVersion);
        if (!MyAbstractClassVersion.Equals(ImplementedVersion))
          throw new InvalidOperationException(message);
    }
}


public class ConcreteClass : MyAbstractClass
{
    public ConcreteClass() : base() {
        // ConcreteClass is guaranteed to have
        // a constructor that calls the base constructor
        // I just simplified the example
}

    public override int ImplementedVersion
    {
        get { return 2; }
    }
}

As you see, I call CheckVersion() from the abstract constructor, to get rid of the "virtual member call in base constructor" message, but I am not sure if that's really the way to do it. Sure, it works, but that doesn't mean it will always work, will it?

Also, I wonder if I can get the name of the Concrete Type from the CheckVersion() function?

I know that adding new abstract members will force an error anyway (System.TypeLoadException) and I'm not sure if I want this type of strict Versioning, but I'm just curious how it would be done properly given only the abstract class and an implementation (I know I could do it by using interfaces and/or a Factory pattern).

+3  A: 

Well, you're only fooling the static analysis - you're still doing a virtual call in the ctor. If it is needed during the ctor, perhaps instead this should be a required base-constructor value, that subclasses pass down:

protected BaseType(int version) { /* store etc */ }

public DerivedType() : base(3) {...}

Or perhaps do it in something that is fixed at compile - attributes:

[YourVersion(3)]
public class DerivedType {...}

and look this up via reflection on:

YourVersionAttribute attrib = (YourVersionAttribute)
     Attribute.GetCustomAttribute(GetType(), typeof(YourVersionAttribute));
int version = attrib == null ? -1 : attrib.Version;
Marc Gravell
The Attribute approach is interesting. Maybe overkill here, but I'll add it to my list of "Good stuff to know in case I need it". Just to confirm: As Attributes are set on a Type rather than an instance, and as GetType from an abstract class always returns the concrete implementation, this is completely safe to do?
Michael Stum
@Michael - yes; `GetType()` is non-virtual, so you're good to go.
Marc Gravell