How to return generic abstract class ?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • kkris1983
    New Member
    • Mar 2009
    • 8

    How to return generic abstract class ?

    Hi there!

    I have something like this:
    Code:
        abstract class BaseClass<T>
        {
            protected BaseClass(){}
        }
        
        class Class1 : BaseClass<Class1>
        {
            public static Class1 Instance = new Class1();
            private Class1(){}			
        }
        
        class Class2 : BaseClass<Class2>
        {
            public static Class2 Instance = new Class2();
            private Class2(){}		
        }
        
        ...
        public BaseClass<T> Method<T>(int z) where T: BaseClass<T>
        {
            switch(z)
            {
                case 1: 
                    return Class1.Instance;
                case 2:
                    return Class2.Instance;
            }
        }
    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.
    Last edited by PRR; Mar 11 '09, 09:54 AM. Reason: Please post code in [code] [/code] tags.
  • vekipeki
    Recognized Expert New Member
    • Nov 2007
    • 229

    #2
    Please use CODE tags when posting, it makes your code much easier to read.

    How about something like this:
    Code:
    abstract class BaseClass<T>
    {
        public abstract T Instance { get; }
    }
    
    class Class1 : BaseClass<Class1>
    {
        private Class1() { }
    
        readonly Class1 _instance = new Class1();
        public override Class1 Instance
        {
            get { return _instance; }
        }
    }
    
    class Class2 : BaseClass<Class2>
    {
        private Class2() { }
    
        readonly Class2 _instance = new Class2();
        public override Class2 Instance
        {
            get { return _instance; }
        }
    }
    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.

    Comment

    • kkris1983
      New Member
      • Mar 2009
      • 8

      #3
      Originally posted by vekipeki
      Please use CODE tags when posting, it makes your code much easier to read.

      How about something like this:
      Code:
      abstract class BaseClass<T>
      {
          public abstract T Instance { get; }
      }
      
      class Class1 : BaseClass<Class1>
      {
          private Class1() { }
      
          readonly Class1 _instance = new Class1();
          public override Class1 Instance
          {
              get { return _instance; }
          }
      }
      
      class Class2 : BaseClass<Class2>
      {
          private Class2() { }
      
          readonly Class2 _instance = new Class2();
          public override Class2 Instance
          {
              get { return _instance; }
          }
      }
      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.
      Thank You for response,
      Sorry I am newbie here, next time I will use CODE tags. My question concerns
      Code:
       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 ?

      Comment

      • vekipeki
        Recognized Expert New Member
        • Nov 2007
        • 229

        #4
        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:
        Code:
        BaseClass<Class1> obj = Method<Class1>(2);
        Your Method<T> would then return BaseClass<Class 2>, which is not BaseClass<Class 1>.

        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).

        Comment

        • kkris1983
          New Member
          • Mar 2009
          • 8

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

          Code:
          public abstract class StorageBaseAbstract<T> where T : StorageBaseAbstract<T>
          	{
          		#region Singleton
          
          		private static T _instance;
                  protected StorageBaseAbstract() { }
          
          		protected static bool Initialised
          		{
          			get
          			{
          				return _instance != null;
          			}
          		}
          		
          		protected static void Init(T newInstance)
          		{
          			if (newInstance == null)
          				throw new ArgumentNullException();
          
          			_instance = newInstance;
          		}
          
          		protected static T UniqueInstance
          		{
          			get
          			{
          				return Initialised ? SingletonCreator.instance : null;
          			}
          		}
                  
          		private class SingletonCreator
          		{
          			internal static readonly T instance = _instance;
          			static SingletonCreator() { }
                  }
          
          		#endregion
          
          		public abstract Guid Put(byte[] bytaArray);
          		public abstract byte[] Get(Guid guid);
          	}
          
          	public sealed class StorageMemory : StorageBaseAbstract<StorageMemory>
          	{
          		public static StorageMemory Instance
          		{
          			get
          			{
          				if (!Initialised)
          					Init(new StorageMemory());
          				return UniqueInstance;
          			}
          		}
          
          		private StorageMemory() { }
          
          		#region Members
          
          		public override Guid Put(ToProcessObject obj)
          		{
          			return UniqueUserState.Instance.SaveObject(obj);
          		}
          
          		public override ToProcessObject Get(Guid guid)
          		{
          			return UniqueUserState.Instance.LoadObject(guid);
          		}
          
          		#endregion
          	}
          
          public sealed class StorageDataBase : StorageBaseAbstract<StorageDataBase>
          {}
          
          public sealed class StorageFileSystem : StorageBaseAbstract<StorageFileSystem>
          {}
          and I would like to use that "StorageBaseAbs tract<T>" class in factory pattern like:

          Code:
          public StorageBaseAbstract<T> GetStorage<T>(StorageType type) where T : StorageBaseAbstract<T>
          		{
          			switch (type)
          			{
          				case StorageType.DataBase:
          					return StorageDataBase.Instance;
          				case StorageType.FileSystem:
          					return StorageFileSystem.Instance;
          				case StorageType.Memory:
          					return StorageMemory.Instance;
          				default:
          					throw new ArgumentException("Invalid type.", "type");
          			}
          		}
          I hope now it is clear what I want to do.
          Of course I can make it works like:

          Code:
          public object GetStorage(StorageType type)
          {
          			switch (type)
          			{
          				case StorageType.DataBase:
          					return StorageDataBase.Instance;
          				case StorageType.FileSystem:
          					return StorageFileSystem.Instance;
          				case StorageType.Memory:
          					return StorageMemory.Instance;
          				default:
          					throw new ArgumentException("Invalid type.", "type");
          			}
          		}
          but that is not my point.

          Comment

          • kkris1983
            New Member
            • Mar 2009
            • 8

            #6
            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:
            Code:
            public BaseClass<T> Method<T>(int z) where T: BaseClass<T>
            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 ?

            Comment

            • vekipeki
              Recognized Expert New Member
              • Nov 2007
              • 229

              #7
              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 (StorageBaseAbs tract<T>), then you could simply get the singleton using:

              Code:
              StorageDataBase db = StorageDataBase.Instance;
              or

              Code:
              StorageDataBase db = StorageBaseAbstract<StorageDataBase>.Instance;

              But the first thing that bothers me is that it is not very obvious what the StorageBaseAbst ract 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:
              Code:
              public class StorageMemory
              {
              	private static readonly StorageMemory _singleton
                           = new StorageMemory();
              	public static StorageMemory Instance
              	{
              		get
              		{
              			return _singleton;
              		}
              	}
              
              	private StorageMemory() { }
              }

              Comment

              • kkris1983
                New Member
                • Mar 2009
                • 8

                #8
                the thing was I wanted to make an abstract class that its descendants will be instantly Singleton one. That is solution from:
                While it is a bit tricky to implement the Singleton pattern in C#, the steps necessary are well known. There has however been debate about a generic solution for this. This paper provides 3 possible solutions for the generic singleton, and makes a brief comparison.


                My problem has solution:
                there it is...
                The home for technical questions and answers at Microsoft. Get started asking, answering, and browsing questions about products like .Net, Azure, or Teams.


                Thank You for Your kind assisstance!

                Comment

                • vekipeki
                  Recognized Expert New Member
                  • Nov 2007
                  • 229

                  #9
                  But the example in the first article looks like this:

                  Code:
                  public class Singleton<T> where T : class
                  {
                      Singleton() { }
                   
                      class SingletonCreator
                      {
                          static SingletonCreator() { }
                   
                          private static T CreateInstance()
                          {
                              ConstructorInfo constructorInfo = typeof(T).GetConstructor(BindingFlags.Instance |
                                  BindingFlags.NonPublic, Type.DefaultBinder, Type.EmptyTypes, null);
                   
                              if (constructorInfo != null)
                              {
                                  return constructorInfo.Invoke(null) as T;
                              }
                              else
                              {
                                  // alternatively, throw an exception indicating the type parameter
                                  // should have a private parameterless constructor
                                  return null;
                              }
                          }
                   
                          internal static readonly T instance = CreateInstance();
                      }
                  
                  
                      public static T UniqueInstance
                      {
                          get { return SingletonCreator.instance; }
                      }
                  }
                  Then if you add a parameterless ctor to your class
                  Code:
                  public class DatabaseStorage
                  {
                       private DatabaseStorage() {}
                  }
                  You can simply access (or create) the singleton using:
                  Code:
                  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.

                  Comment

                  • kkris1983
                    New Member
                    • Mar 2009
                    • 8

                    #10
                    "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

                    Comment

                    • kkris1983
                      New Member
                      • Mar 2009
                      • 8

                      #11
                      Originally posted by vekipeki
                      But the example in the first article looks like this:

                      Code:
                      public class Singleton<T> where T : class
                      {
                          Singleton() { }
                       
                          class SingletonCreator
                          {
                              static SingletonCreator() { }
                       
                              private static T CreateInstance()
                              {
                                  ConstructorInfo constructorInfo = typeof(T).GetConstructor(BindingFlags.Instance |
                                      BindingFlags.NonPublic, Type.DefaultBinder, Type.EmptyTypes, null);
                       
                                  if (constructorInfo != null)
                                  {
                                      return constructorInfo.Invoke(null) as T;
                                  }
                                  else
                                  {
                                      // alternatively, throw an exception indicating the type parameter
                                      // should have a private parameterless constructor
                                      return null;
                                  }
                              }
                       
                              internal static readonly T instance = CreateInstance();
                          }
                      
                      
                          public static T UniqueInstance
                          {
                              get { return SingletonCreator.instance; }
                          }
                      }
                      Then if you add a parameterless ctor to your class
                      Code:
                      public class DatabaseStorage
                      {
                           private DatabaseStorage() {}
                      }
                      You can simply access (or create) the singleton using:
                      Code:
                      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.
                      I meant preceding example
                      Code:
                      public abstract class AbstractGenericSingleton<T> where T : AbstractGenericSingleton<T>
                      
                      {
                      
                          private static T _instance;
                      
                       
                      
                          protected static bool Initialised
                      
                          {
                      
                              get
                      
                              {
                      
                                  return (_instance != null);
                      
                              }
                      
                          }
                      
                       
                      
                          protected static T UniqueInstance
                      
                          {
                      
                              get
                      
                              {
                      
                                  if (Initialised)
                      
                                  {
                      
                                      return SingletonCreator.instance;
                      
                                  }
                      
                                  else
                      
                                  {
                      
                                      return null;
                      
                                  }
                      
                              }
                      
                          }
                      
                       
                      
                          protected AbstractGenericSingleton() { }
                      
                       
                      
                          protected static void Init(T newInstance)
                      
                          {
                      
                              if (newInstance == null) throw new ArgumentNullException();
                      
                       
                      
                              _instance = newInstance;
                      
                          }
                      
                       
                      
                          class SingletonCreator
                      
                          {
                      
                              static SingletonCreator() { }
                      
                       
                      
                              internal static readonly T instance = _instance;
                      
                          }
                      
                       
                      
                      }
                      
                       
                      
                      public sealed class ReadyForGenericSingleton : AbstractGenericSingleton<ReadyForGenericSingleton>
                      
                      {
                      
                          public static ReadyForGenericSingleton Instance
                      
                          {
                      
                              get
                      
                              {
                      
                                  if (!Initialised)
                      
                                  {
                      
                                      Init(new ReadyForGenericSingleton());
                      
                                  }
                      
                       
                      
                                  return UniqueInstance;
                      
                              }
                      
                          }
                      
                       
                      
                          private ReadyForGenericSingleton() { }
                      
                      }

                      Comment

                      • vekipeki
                        Recognized Expert New Member
                        • Nov 2007
                        • 229

                        #12
                        As I said, that example doesn't help you a lot.

                        Because this code:

                        Code:
                        public sealed class ReadyForGenericSingleton : AbstractGenericSingleton<ReadyForGenericSingleton>
                        {
                            public static ReadyForGenericSingleton Instance
                            {
                                get
                                {
                                    if (!Initialised)
                                    {
                                        Init(new ReadyForGenericSingleton());
                                    }
                                    return UniqueInstance;
                                }
                            }
                        
                            private ReadyForGenericSingleton() { }
                        }
                        ...is not much smaller than this code:

                        Code:
                        public sealed class ReadyForGenericSingleton
                        {
                            private static ReadyForGenericSingleton _instance
                               = new ReadyForGenericSingleton();
                            public static ReadyForGenericSingleton Instance
                            {
                                get
                                {
                                    return _instance;
                                }
                            }
                        
                            private ReadyForGenericSingleton() { }
                        }
                        If you use the last example (reflection), you don't need to write anything in your actual class.

                        Comment

                        • kkris1983
                          New Member
                          • Mar 2009
                          • 8

                          #13
                          I did use reflection code :) Thanks

                          Comment

                          Working...