By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,985 Members | 1,830 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,985 IT Pros & Developers. It's quick & easy.

How to return generic abstract class ?

P: 8
Hi there!

I have something like this:
Expand|Select|Wrap|Line Numbers
  1.     abstract class BaseClass<T>
  2.     {
  3.         protected BaseClass(){}
  4.     }
  5.  
  6.     class Class1 : BaseClass<Class1>
  7.     {
  8.         public static Class1 Instance = new Class1();
  9.         private Class1(){}            
  10.     }
  11.  
  12.     class Class2 : BaseClass<Class2>
  13.     {
  14.         public static Class2 Instance = new Class2();
  15.         private Class2(){}        
  16.     }
  17.  
  18.     ...
  19.     public BaseClass<T> Method<T>(int z) where T: BaseClass<T>
  20.     {
  21.         switch(z)
  22.         {
  23.             case 1: 
  24.                 return Class1.Instance;
  25.             case 2:
  26.                 return Class2.Instance;
  27.         }
  28.     }
  29.  
That is very important that those classes cannot be instantiated since their construstors are private so we cannot do like

`public BaseClass<T> Method<T>(int z) where T: BaseClass<T>,` **new()**

How can I use abstract class as return type ?? I just can not work this out. Would appreciate for any assisstance here.
Mar 9 '09 #1
Share this Question
Share on Google+
12 Replies


vekipeki
Expert 100+
P: 229
Please use CODE tags when posting, it makes your code much easier to read.

How about something like this:
Expand|Select|Wrap|Line Numbers
  1. abstract class BaseClass<T>
  2. {
  3.     public abstract T Instance { get; }
  4. }
  5.  
  6. class Class1 : BaseClass<Class1>
  7. {
  8.     private Class1() { }
  9.  
  10.     readonly Class1 _instance = new Class1();
  11.     public override Class1 Instance
  12.     {
  13.         get { return _instance; }
  14.     }
  15. }
  16.  
  17. class Class2 : BaseClass<Class2>
  18. {
  19.     private Class2() { }
  20.  
  21.     readonly Class2 _instance = new Class2();
  22.     public override Class2 Instance
  23.     {
  24.         get { return _instance; }
  25.     }
  26. }
Compiler cannot know know that Instance is of type T (or BaseClass<T>), if it is static, so you have to do it like this.
Mar 9 '09 #2

P: 8
@vekipeki
Thank You for response,
Sorry I am newbie here, next time I will use CODE tags. My question concerns
Expand|Select|Wrap|Line Numbers
  1.  BaseClass<T> Method<T>(int z) where T: BaseClass<T>
method how to make it work... Properties cannot be inherited in my solution it is a bit complicated. Is there a way to make that Method<T> work like I wrote it ?
Mar 9 '09 #3

vekipeki
Expert 100+
P: 229
The important thing to notice here is that Class1.Instance is of type Class1, while Class2.Instance is of type Class2. Since they are both static and are not defined in any interface or parent abstract class, for C# compiler they are completely different.

You are telling compiler that T should be derived from BaseClass<T>, but you are not telling him that T is Class1 or Class2, so it doesn't want to allow that.

What would happen if your code would compile without errors, and somebody wrote this:
Expand|Select|Wrap|Line Numbers
  1. BaseClass<Class1> obj = Method<Class1>(2);
Your Method<T> would then return BaseClass<Class2>, which is not BaseClass<Class1>.

Properties cannot be inherited in my solution it is a bit complicated.
Why not?

I think the way you're trying to code it right now is a bit complicated, so try to explain what you are trying to do and then maybe it would be easier to point you in the right direction.

From your code, it looks like Method<T> should belong to the abstract class, in which case you need to be able to get an instance of T somehow (either by having a public constructor, or by using an abstract property).
Mar 9 '09 #4

P: 8
You are right there I just noticed that simple skeleton lacked on some things... ok there is whole code:

Expand|Select|Wrap|Line Numbers
  1. public abstract class StorageBaseAbstract<T> where T : StorageBaseAbstract<T>
  2.     {
  3.         #region Singleton
  4.  
  5.         private static T _instance;
  6.         protected StorageBaseAbstract() { }
  7.  
  8.         protected static bool Initialised
  9.         {
  10.             get
  11.             {
  12.                 return _instance != null;
  13.             }
  14.         }
  15.  
  16.         protected static void Init(T newInstance)
  17.         {
  18.             if (newInstance == null)
  19.                 throw new ArgumentNullException();
  20.  
  21.             _instance = newInstance;
  22.         }
  23.  
  24.         protected static T UniqueInstance
  25.         {
  26.             get
  27.             {
  28.                 return Initialised ? SingletonCreator.instance : null;
  29.             }
  30.         }
  31.  
  32.         private class SingletonCreator
  33.         {
  34.             internal static readonly T instance = _instance;
  35.             static SingletonCreator() { }
  36.         }
  37.  
  38.         #endregion
  39.  
  40.         public abstract Guid Put(byte[] bytaArray);
  41.         public abstract byte[] Get(Guid guid);
  42.     }
  43.  
  44.     public sealed class StorageMemory : StorageBaseAbstract<StorageMemory>
  45.     {
  46.         public static StorageMemory Instance
  47.         {
  48.             get
  49.             {
  50.                 if (!Initialised)
  51.                     Init(new StorageMemory());
  52.                 return UniqueInstance;
  53.             }
  54.         }
  55.  
  56.         private StorageMemory() { }
  57.  
  58.         #region Members
  59.  
  60.         public override Guid Put(ToProcessObject obj)
  61.         {
  62.             return UniqueUserState.Instance.SaveObject(obj);
  63.         }
  64.  
  65.         public override ToProcessObject Get(Guid guid)
  66.         {
  67.             return UniqueUserState.Instance.LoadObject(guid);
  68.         }
  69.  
  70.         #endregion
  71.     }
  72.  
  73. public sealed class StorageDataBase : StorageBaseAbstract<StorageDataBase>
  74. {}
  75.  
  76. public sealed class StorageFileSystem : StorageBaseAbstract<StorageFileSystem>
  77. {}
  78.  
and I would like to use that "StorageBaseAbstract<T>" class in factory pattern like:

Expand|Select|Wrap|Line Numbers
  1. public StorageBaseAbstract<T> GetStorage<T>(StorageType type) where T : StorageBaseAbstract<T>
  2.         {
  3.             switch (type)
  4.             {
  5.                 case StorageType.DataBase:
  6.                     return StorageDataBase.Instance;
  7.                 case StorageType.FileSystem:
  8.                     return StorageFileSystem.Instance;
  9.                 case StorageType.Memory:
  10.                     return StorageMemory.Instance;
  11.                 default:
  12.                     throw new ArgumentException("Invalid type.", "type");
  13.             }
  14.         }
  15.  
I hope now it is clear what I want to do.
Of course I can make it works like:

Expand|Select|Wrap|Line Numbers
  1. public object GetStorage(StorageType type)
  2. {
  3.             switch (type)
  4.             {
  5.                 case StorageType.DataBase:
  6.                     return StorageDataBase.Instance;
  7.                 case StorageType.FileSystem:
  8.                     return StorageFileSystem.Instance;
  9.                 case StorageType.Memory:
  10.                     return StorageMemory.Instance;
  11.                 default:
  12.                     throw new ArgumentException("Invalid type.", "type");
  13.             }
  14.         }
  15.  
but that is not my point.
Mar 9 '09 #5

P: 8
By the way... the thing You wrote about
"Method<T> should belong to the abstract class, in which case you need to be able to get an instance of T"

that code:
Expand|Select|Wrap|Line Numbers
  1. public BaseClass<T> Method<T>(int z) where T: BaseClass<T>
  2.  
says itself ( " where T: BaseClass<T>" ) that T must be BaseClass or class that inherits it... so in switch statement we return Class1 or Class2 that are descendants so it should work, or I am wrong ?
Mar 9 '09 #6

vekipeki
Expert 100+
P: 229
To call the GetStorage<T> method, you already need to know the type of T, so it isn't actually a factory.

I still don't understand why Instance needs to be static. If it was public and abstract in your base class (StorageBaseAbstract<T>), then you could simply get the singleton using:

Expand|Select|Wrap|Line Numbers
  1. StorageDataBase db = StorageDataBase.Instance;
or

Expand|Select|Wrap|Line Numbers
  1. StorageDataBase db = StorageBaseAbstract<StorageDataBase>.Instance;

But the first thing that bothers me is that it is not very obvious what the StorageBaseAbstract class does. It looks like you are only using it to save a static singleton instance of your derived classes. Furthermore, none of its methods is public, so it really doesn't do anything.

Why don't you just write:
Expand|Select|Wrap|Line Numbers
  1. public class StorageMemory
  2. {
  3.     private static readonly StorageMemory _singleton
  4.              = new StorageMemory();
  5.     public static StorageMemory Instance
  6.     {
  7.         get
  8.         {
  9.             return _singleton;
  10.         }
  11.     }
  12.  
  13.     private StorageMemory() { }
  14. }
Mar 9 '09 #7

P: 8
the thing was I wanted to make an abstract class that its descendants will be instantly Singleton one. That is solution from:
http://www.c-sharpcorner.com/UploadF...Singleton.aspx

My problem has solution:
there it is...
http://social.msdn.microsoft.com/For...4-2476cb64c994

Thank You for Your kind assisstance!
Mar 9 '09 #8

vekipeki
Expert 100+
P: 229
But the example in the first article looks like this:

Expand|Select|Wrap|Line Numbers
  1. public class Singleton<T> where T : class
  2. {
  3.     Singleton() { }
  4.  
  5.     class SingletonCreator
  6.     {
  7.         static SingletonCreator() { }
  8.  
  9.         private static T CreateInstance()
  10.         {
  11.             ConstructorInfo constructorInfo = typeof(T).GetConstructor(BindingFlags.Instance |
  12.                 BindingFlags.NonPublic, Type.DefaultBinder, Type.EmptyTypes, null);
  13.  
  14.             if (constructorInfo != null)
  15.             {
  16.                 return constructorInfo.Invoke(null) as T;
  17.             }
  18.             else
  19.             {
  20.                 // alternatively, throw an exception indicating the type parameter
  21.                 // should have a private parameterless constructor
  22.                 return null;
  23.             }
  24.         }
  25.  
  26.         internal static readonly T instance = CreateInstance();
  27.     }
  28.  
  29.  
  30.     public static T UniqueInstance
  31.     {
  32.         get { return SingletonCreator.instance; }
  33.     }
  34. }
Then if you add a parameterless ctor to your class
Expand|Select|Wrap|Line Numbers
  1. public class DatabaseStorage
  2. {
  3.      private DatabaseStorage() {}
  4. }
You can simply access (or create) the singleton using:
Expand|Select|Wrap|Line Numbers
  1. DatabaseStorage dbStorage = Singleton<DatabaseStorage>.UniqueInstance;
But note that UniqueInstance is public and created in abstract class.

Writing code to create an instance each time (in each derived class) doesn't make any sense (StorageMemory.Instance, for example) - what's the point in having an abstract class then?

Note that you also don't need to inherit from Singleton<T>, it is only a helper class to avoid writing singleton code multiple times.
Mar 9 '09 #9

P: 8
"it is only a helper class to avoid writing singleton code multiple times" that is what i wanted to achieve there... yeah now I get Your point with that public property in abstract class, that is correct, thank You for advice
Mar 9 '09 #10

P: 8
@vekipeki
I meant preceding example
Expand|Select|Wrap|Line Numbers
  1. public abstract class AbstractGenericSingleton<T> where T : AbstractGenericSingleton<T>
  2.  
  3. {
  4.  
  5.     private static T _instance;
  6.  
  7.  
  8.  
  9.     protected static bool Initialised
  10.  
  11.     {
  12.  
  13.         get
  14.  
  15.         {
  16.  
  17.             return (_instance != null);
  18.  
  19.         }
  20.  
  21.     }
  22.  
  23.  
  24.  
  25.     protected static T UniqueInstance
  26.  
  27.     {
  28.  
  29.         get
  30.  
  31.         {
  32.  
  33.             if (Initialised)
  34.  
  35.             {
  36.  
  37.                 return SingletonCreator.instance;
  38.  
  39.             }
  40.  
  41.             else
  42.  
  43.             {
  44.  
  45.                 return null;
  46.  
  47.             }
  48.  
  49.         }
  50.  
  51.     }
  52.  
  53.  
  54.  
  55.     protected AbstractGenericSingleton() { }
  56.  
  57.  
  58.  
  59.     protected static void Init(T newInstance)
  60.  
  61.     {
  62.  
  63.         if (newInstance == null) throw new ArgumentNullException();
  64.  
  65.  
  66.  
  67.         _instance = newInstance;
  68.  
  69.     }
  70.  
  71.  
  72.  
  73.     class SingletonCreator
  74.  
  75.     {
  76.  
  77.         static SingletonCreator() { }
  78.  
  79.  
  80.  
  81.         internal static readonly T instance = _instance;
  82.  
  83.     }
  84.  
  85.  
  86.  
  87. }
  88.  
  89.  
  90.  
  91. public sealed class ReadyForGenericSingleton : AbstractGenericSingleton<ReadyForGenericSingleton>
  92.  
  93. {
  94.  
  95.     public static ReadyForGenericSingleton Instance
  96.  
  97.     {
  98.  
  99.         get
  100.  
  101.         {
  102.  
  103.             if (!Initialised)
  104.  
  105.             {
  106.  
  107.                 Init(new ReadyForGenericSingleton());
  108.  
  109.             }
  110.  
  111.  
  112.  
  113.             return UniqueInstance;
  114.  
  115.         }
  116.  
  117.     }
  118.  
  119.  
  120.  
  121.     private ReadyForGenericSingleton() { }
  122.  
  123. }
Mar 11 '09 #11

vekipeki
Expert 100+
P: 229
As I said, that example doesn't help you a lot.

Because this code:

Expand|Select|Wrap|Line Numbers
  1. public sealed class ReadyForGenericSingleton : AbstractGenericSingleton<ReadyForGenericSingleton>
  2. {
  3.     public static ReadyForGenericSingleton Instance
  4.     {
  5.         get
  6.         {
  7.             if (!Initialised)
  8.             {
  9.                 Init(new ReadyForGenericSingleton());
  10.             }
  11.             return UniqueInstance;
  12.         }
  13.     }
  14.  
  15.     private ReadyForGenericSingleton() { }
  16. }
...is not much smaller than this code:

Expand|Select|Wrap|Line Numbers
  1. public sealed class ReadyForGenericSingleton
  2. {
  3.     private static ReadyForGenericSingleton _instance
  4.        = new ReadyForGenericSingleton();
  5.     public static ReadyForGenericSingleton Instance
  6.     {
  7.         get
  8.         {
  9.             return _instance;
  10.         }
  11.     }
  12.  
  13.     private ReadyForGenericSingleton() { }
  14. }
If you use the last example (reflection), you don't need to write anything in your actual class.
Mar 11 '09 #12

P: 8
I did use reflection code :) Thanks
Mar 11 '09 #13

Post your reply

Sign in to post your reply or Sign up for a free account.