Anonymous
Anonymous

Reputation: 1978

Pass type parameter through several derived classes for using in generic static constructor

I have some generic template for multiton or objects pool.

public class A<TC> where TC : class, new()
{
    protected static ConcurrentDictionary<object, TC> _instances = new ConcurrentDictionary<object, TC>();

    public static TC Instance(object key)
    {
        return _instances.GetOrAdd(key, k => new TC());
    }
}

// One level inheritance works as expected    

public class B : A<B> 
{
    public virtual int Demo() { return 1; }
}

// Class C is example of what I want    
// How to override method from B, pass C to A and use it in GetInstance?

public class C : B<C>
{
    public override int Demo() { return 2; }
}

Question : I want class C to override method from B, how can I pass type parameter "C" through the chain of child classes to use it with method Instance() from A, is it possible at all?

I tried to modify B but seems that it makes it generic and does not allow to instantiate B :

public class B<TC> : A<TC> where TC : class, new()
{
    public virtual int Demo() { return 1; }
}

Update : the idea is to have generic static constructor, then I derive class Memory from it that works with memory mapped files, but this class can read and write only bytes sequence in and out, thus, I create class MemoryStructs derived from Memory and this class can read and write whole structures, of course, I can put all these methods into Memory but I thought it may be useful to split them logically, thus, I have such inheritance chain : BaseClass > Memory > MemoryStructs

Memory and MemoryStructs classes have method OpenMemory and CloseMemory and I'm not willing to duplicate those methods for each of them, thus I need either :

Upvotes: 2

Views: 1071

Answers (3)

Mehrzad Chehraz
Mehrzad Chehraz

Reputation: 5147

Maybe you need another class in the chain?

public class B1<T> : A<B1<T>> 
{
    public virtual int Demo() { return 1; }
}
public class B2 : B1<B2>
{
    // Something that C does not do
}
public class C : B1<C>
{
   public override int Demo() { return 2; }
}

Edit:

Seems like that you want to inherit some functionality of B and pass a type argument to it in C meanwhile you want to define B as a non-generic class, that's not possible, B must be either non-generic that you don't have C : B<C> anymore:

public class B : A<B>
{
    public virtual int Demo() { return 1; }
}
public class C : B
{
   public override int Demo() { return 2; }
}

or it must be generic so you can't pass B as a type argument to A:

public class B<T> : A<T>
{
    public virtual int Demo() { return 1; }
}
public class C : B<T>
{
   public override int Demo() { return 2; }
}

or you may choose to use the composition pattern and create an instance of B in C so that you can use it's functionality in C:

public class B : A<B>
{
    public virtual int Demo() { return 1; }
}
public class C : A<C>
{
   private B b = new B();
   public override int Demo() {
      // Maybe use b here
      return 2;
   }
}

Upvotes: 1

Mikko Viitala
Mikko Viitala

Reputation: 8404

@David Amo is absolutely correct. Maybe this is what you are after?

public abstract class A<TC> where TC : class, new()
{
    protected static ConcurrentDictionary<object, TC> _instances = 
        new ConcurrentDictionary<object, TC>();

    public static TC Instance(object key)
    {
        return _instances.GetOrAdd(key, k => new TC());
    }

    public abstract int Demo();
}

public class B : A<B>
{
    public override int Demo() { return 1; }
}

public class C : A<C>
{
    public override int Demo() { return 2; }
}

Upvotes: 1

poke
poke

Reputation: 387915

Instance is a static method of A<TC> so there does not even exist an Instance method in B which you could override (even if you could, the TC type parameter would be bound to B by then, so a method returning C would be a different method).

So the way you call Instance is using A<TC>.Instance(key) where TC is an actual type. So for example:

B objectB = A<B>.Instance(key)
C objectC = A<C>.Instance(key)

Note that the concurrent dictionary is separate for each type parameter TC, so A<B> and A<C> do not share the same dictionary; they are different types with separate static members.

Upvotes: 2

Related Questions