Is there a more automatic way to wrap those interfaces

Go To StackoverFlow.com

2

I'm doing a multiplatform thing, but I'm not very good with OOP. Currently my code is:

    public interface IMessageBox {
        void Show(string Text);
        void Show(string Text, string Description, MessageBoxType Type);
        MessageBoxResult ShowYesNo(string Text, string Description, MessageBoxType Type);
        MessageBoxResult ShowYesNoCancel(string Text, string Description, MessageBoxType Type);
    }

    public class MessageBox : InstanceGenerator {
        public static void Show(string Text) {
            MessageBoxImpl.Show(Text);
        }

        public static void Show(string Text, string Description, MessageBoxType Type) {
            MessageBoxImpl.Show(Text, Description, Type);
        }
        public static MessageBoxResult ShowYesNo(string Text, string Description, MessageBoxType Type) {
            return MessageBoxImpl.ShowYesNo(Text, Description, Type);
        }
        public static MessageBoxResult ShowYesNoCancel(string Text, string Description, MessageBoxType Type) {
            return MessageBoxImpl.ShowYesNoCancel(Text, Description, Type);
        }
    }

protected class InstanceGenerator {
        public static IMessageBox MessageBoxImpl = null;
        public static IWindow WindowImpl = null;

        private static Assembly Instance = null;
        private static string InstanceName = null;

        private static Assembly LoadAssembly(string lib) {
            string AppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Assembly assembly = Assembly.LoadFile(Path.Combine(AppPath, lib + ".dll"));
            return assembly;
        }

        private static object CreateInstance(string @class) {
            Type type = Instance.GetType(InstanceName + "." + @class);
            return Activator.CreateInstance(type);
        }

        private static object CreateInstanceFromPath(string lib, string @class) {
            string AppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Assembly assembly = Assembly.LoadFile(Path.Combine(AppPath, lib + ".dll"));
            Type type = assembly.GetType(lib + "." + @class);
            return Activator.CreateInstance(type);
        }


        /// <summary>
        /// Inits the whole thing
        /// </summary>
        public static void Init() {
            if (CurrentOS.IsWindows)
                InstanceName = "Lib.Windows";
            else if (CurrentOS.IsMac)
                InstanceName = "Lib.MacOS";
            else if (CurrentOS.IsLinux)
                InstanceName = "Lib.Linux";
            else // no implementation for other OSes
                throw new Exception("No implementation of Lib for this OS");

            Instance = LoadAssembly(InstanceName);

            // initialize the classes
            MessageBoxImpl = (IMessageBox) CreateInstance("MessageBox");
        }
    }

EDIT:

Where InstanceGenerator returns an instance of the IMessageBox loaded from an assembly. Is there a better way to create/connect to an instance? Implementing all the same static methods looks not good soltution at all. Is there a more automatic way to wrap those interfaces with a class or I'm doing something wrong?

2012-04-04 19:08
by blez


4

You're not currently implementing the interface. You can't use static methods to implement an interface. You have to use instance methods. You can call static methods within the implementation, of course, but that's a different matter.

It doesn't sound like MessageBox should derive from InstanceGenerator - I'd suggest that it should compose it:

public class MessageBox : IMessageBox {

    private readonly InstanceGenerator generator;

    public MessageBox(InstanceGenerator generator) {
        this.generator = generator;
    }

    public static void Show(string Text) {
        generator.MessageBoxImpl.Show(Text);
    }

    public static void Show(string text, string description, MessageBoxType type) {
        generator.MessageBoxImpl.Show(text, description, type);
    }

    public static MessageBoxResult ShowYesNo(string text, string description, 
                                             MessageBoxType type) {
        return generator.MessageBoxImpl.ShowYesNo(text, description, type);
    }

    public static MessageBoxResult ShowYesNoCancel(string text,
                                                   string description,
                                                   MessageBoxType type) {
        return generator.MessageBoxImpl.ShowYesNoCancel(text, description, type);
    }
}

I'm assuming that MessageBoxImpl doesn't already implement IMessageBox as otherwise all of this is pretty pointless...

2012-04-04 19:10
by Jon Skeet
Please check my edit for the InstanceGenerator class - blez 2012-04-04 19:18
@blez: Okay, it's even less clear what you're intending to do here. What's the point of the MessageBox class - Jon Skeet 2012-04-04 19:20
The code is written that way cause i want to use static methods of MessageBox class, just like WinForms - blez 2012-04-04 19:21
@blez: so why not just call InstanceGenerator.MessageBoxImpl.Xyz? It would be clearer... to be honest, I'd recommend trying to avoid static methods where possible, as they make your code much harder to test - Jon Skeet 2012-04-04 19:23
Cause InstanceGenerator.MessageBoxImpl.Xyz looks uglier than MessageBox.Xyz. That's a library, the code should look well. So I'm not doing anything wrong - blez 2012-04-04 19:24
@blez: Well yes, I'd say that from a design point of view you're writing code which is hard to test by using static methods. Instead, it would be better to inject an IMessageBox into everything that needs it - and presumably get that implementation from InstanceGenerator - Jon Skeet 2012-04-04 19:32
Can you give a simple example of that - blez 2012-04-04 19:35
@blez: Make IMessageBox a constructor parameter for any class which needs to use one. There isn't enough space in a comment to talk about dependency injection in depth, but that's what you should be looking into - Jon Skeet 2012-04-04 20:56


1

Your implementation as it stands defines an interface that doesn't actually do anything. The point of an interface is to allow you to write code that says something like:

instance_implementing_interface.DoSomething();

You don't have that. Instead you're defining an interface, then rewriting everything it does using static methods. The idea of an interface is that whatever wants to use an instance to do its job can take any instance which implements that interface, and trust that it does what it says it does (unless you are in the habit of lying to yourself in your own API).

In fact having written the above, I realise that I might have assumed you to be more confused than you actually are - after several re-readings, you seem to understand everything I've said. Which leads me to bafflement as to why you've written the code you have. Could you explain why you've deliberately written static methods in MessageBox?

2012-04-04 19:16
by Tom W
Please check my edit. The code is written that way cause i want to use static methods of MessageBox class, just like WinForms - blez 2012-04-04 19:20
I think I understand your objective now. Are you just trying to make the code appear to be the same for multiple platforms? I can understand that desire, but I'd be hesitant to attempt the same solution. The most obvious reason for this is that it is a lie. This gives the impression that there is global state in your application, whereas underneath it's actually instance-dependent. I would suggest instead just writing the consuming code in a style that takes an instance to handle all the UI interaction, which can call the appropriate platform-specific methods behind the scenes - Tom W 2012-04-04 19:31
Ads