Click here to Skip to main content
14,866,383 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
Can someone please tell me where I am going wrong with the following code? (I'm hoping the answer is not 'Everywhere'.)

My problem is that I can't figure out how to write the factory function to create actual instances of the graphics objects. Specific compiler error of this latest attempt is below the code.

	public abstract class LogicBase {}
	public class LogicSubclassA : LogicBase
	{
		public string LogicSubclassAOnly => "LogicA";
	}
	public class LogicSubclassB : LogicBase
	{
		public string LogicSubclassBOnly => "LogicB";
	}

	public abstract class GraphicsBase<T> where T : LogicBase
	{
		public GraphicsBase( T logicObject ) => LogicObject = (T)logicObject;
		public T LogicObject { get; }
	}

	public class GraphicsSubclassA : GraphicsBase<LogicSubclassA>
	{
		public GraphicsSubclassA( LogicSubclassA logicObject ) : base( logicObject ) {}
		public void SomeFunction()
		{
			Console.WriteLine( LogicObject.LogicSubclassAOnly );
		}
	}

	public class GraphicsSubclassB : GraphicsBase<LogicSubclassB>
	{
		public GraphicsSubclassB( LogicSubclassB logicObject ) : base( logicObject ) {}
		public void SomeFunction()
		{
			Console.WriteLine( LogicObject.LogicSubclassBOnly );
		}
	}


// Please see below the code for the specific compiler error.
	public static class GraphicsObjectFactory
	{
		public static GraphicsBase<LogicBase> CreateInstance( string specificType )
		{
			switch( specificType )
			{
				case "A": return new GraphicsSubclassA( new LogicSubclassA() );
				case "B": return new GraphicsSubclassB( new LogicSubclassB() );
				default: throw new ArgumentException();
			}
		}
	}


The error is: Cannot implicitly convert type GraphicsSubclassA to GraphicsBase<LogicBase>

What I have tried:

I've read multiple articles on the internet about using the Factory Pattern with generics but none seems to help me sort out my specific problem here - mainly because my brain just doesn't seem to be wired to handle generics proficiently.

This question is a follow-on from a previous question I posted here: Previous Question
Posted
Updated 23-Oct-20 5:16am
v3
Comments
CHill60 23-Oct-20 7:41am
   
Follow on or not, what is your specific problem?
Edit - spotted the problem as a comment in your code, but "do not compile" is not helpful - what is the precise error reported?
Patrick Skelton 23-Oct-20 7:53am
   
Sorry - I've (hopefully) improved the question.

Maybe this will be helpful: Generic Factory Class[^]
   
Comments
Patrick Skelton 23-Oct-20 7:56am
   
Mmm... I think your suggestion of this as a solution maybe indicates I haven't worded the title of the question very well. I don't think what I'm trying to do is that complicated. I'm not wanting to be able to swap out factories for example. I think all I am wanting is a factory that can create an instance of a generic class.
I added a comment to your other thread, you're not really using the factory pattern correctly. You need to think about what the calling code is doing and what factory patterns are for. The factory has to return an object that supports an interface that all concrete objects implement. As the calling code doesn't know the specific type you can't have methods with names that are specific to each type, instead you need each concrete object to have the same method name and each concrete object has its own implementation. I think you need to refactor your code, get rid of the wrapper graphics object and work at the logic object level.

C#
public abstract class LogicBase {

    public virtual void SomeFunction()
    {
        Console.WriteLine("Logic Base");
    }
}

public class LogicSubclassA : LogicBase
{
    public string LogicSubclassAOnly => "LogicA";

    public override void SomeFunction()
    {
        Console.WriteLine(LogicSubclassAOnly);
    }
}
public class LogicSubclassB : LogicBase
{
    public string LogicSubclassBOnly => "LogicB";

    public override void SomeFunction()
    {
        Console.WriteLine(LogicSubclassBOnly);
    }
}

public static class LogicObjectFactory
{
    public static LogicBase CreateInstance(string specificType)
    {
        switch (specificType)
        {
            case "A": return new LogicSubclassA();
            case "B": return new LogicSubclassB();
            default: throw new ArgumentException();
        }
    }
}


calling code;

C#
var o = LogicObjectFactory.CreateInstance("A");
o.SomeFunction();

o = LogicObjectFactory.CreateInstance("B");
o.SomeFunction();
   
Comments
BillWoodruff 23-Oct-20 10:18am
   
+5 Works for me !
Patrick Skelton 24-Oct-20 2:39am
   
Thanks for the reply. I really do seem to have done a poor job of asking this question. I put the concrete functions in just to 'test' that my two subclasses are capable of being different; in reality, the only place the code relies on its specific type is inside that specific type. The caller generally doesn't need to know the specific type. Mainly this whole thing was an exercise in avoiding casting. That said, the fact that all of the answers don't seem to line-up with my intent implies I have indeed been over-complicating things. I'll work out something a bit cleaner on Monday and post it if it looks remotely relevant to my original question. Not sure what to do about accepting solutions here. All supply useful information but it my question is poor so none of the solutions seems to be exactly what I am looking for. Any advice on protocol here anyone?
F-ES Sitecore 24-Oct-20 8:56am
   
The main problem with how you're doing it is that you're trying to cast X<A> to X<B> and you'll struggle to do that easily.
Patrick Skelton 25-Oct-20 3:15am
   
That is a very clear way of putting it! Is it still a problem if A and B are themselves subclasses of a common ancestor Z and all I need to do is store a single reference somewhere to X<Z>, while any code specific to X<A> and X<B> is contained privately inside those classes?
Snesh Prajapati[^] has written a nice set of articles at Factory Patterns - Simple Factory Pattern[^].
   
fyi: the DoFactory design-pattern collection (commercial software) has some good tutorials (free): check out their tut on the Factory Pattern: [^]. note: i purchased their software a few years ago, and have learned a lot with/from its rigorously formal consistent content ... and, style.

What you are doing seems overly complicated: see if this code gives you any ideas.

usage:
Dog dog = AnimalFactory.NewAnimal<Dog>("Mangy");

Cat cat = AnimalFactory.NewAnimal<Cat>("Mouser");
code for AnimalFactory:
using System;

namespace YourFactory
{
    public interface IAnimal<T>
    {
        string Name { get; set; }
    }

    public class Dog: IAnimal<Dog>
    {
        public Dog(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
    }

    public class Cat: IAnimal<Cat>
    {
        public Cat(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
    }

    public static class AnimalFactory
    {
        public static T NewAnimal<T>(string name) where T : IAnimal<T>
        {
            return (T) Activator.CreateInstance(typeof(T), name);
        }
    }
}
   
v2
Comments
Patrick Skelton 26-Oct-20 4:48am
   
Hope no one minds but I've accepted this as solution because the provided link points to extremely useful information, and therefore I feel that anyone who might look at my question would best be helped by reading these excellent illustrations of various patterns implemented in C#.
BillWoodruff 26-Oct-20 5:06am
   
I'm glad you found this useful.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900