2

The code is simple enough to understand I hope.

I'm trying to use an interface type IColor in order to pass color objects to the ColorManager. I then want the ColorManager to pass this object to the IColor object as its own type, so the method overloads gets called.

However, it seems since it is being passed as the IColor type, C# will not implicity cast it into its complete type as either a BlueColor or GreenColor.

I hope this makes some sense to somebody on what I want to achieve. Is this possible in C#?

[Solution] http://msdn.microsoft.com/en-us/library/dd264736.aspx Overload Resolution with Arguments of Type dynamic

My code so far:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;

namespace Example
{
    public interface IColor 
    {
        void CatchColor(IColor c);
    }

    public class BlueColor : IColor
    {
        public void CatchColor(IColor c)
        {
        }
    }

    public class GreenColor : IColor
    {
        public void CatchColor(BlueColor c)
        {
            Console.WriteLine("CAUGHT BLUE!");
        }

        public void CatchColor(GreenColor c)
        {
            Console.WriteLine("CAUGHT GREEN!");
        }

        public void CatchColor(IColor c)
        {
            Console.WriteLine("CAUGHT SOME COLOR!");
        }
    }

    public class ColorManager
    {
        public void PassColor(IColor c)
        {
            // Don't use static type-checking
            // Problem solved
            dynamic AnyColor = c;

            AnyColor.CatchColor(AnyColor);
        }

        public static void Main()
        {
            GreenColor G = new GreenColor();
            new ColorManager().PassColor(G);

            Console.ReadLine();
            return;
        }
    }
}
joe.ds
  • 125
  • 1
  • 1
  • 9
  • 4
    This is when you want to use [Generic Methods](http://msdn.microsoft.com/en-us/library/twcad0zb.aspx) :) – Erik Philips Jun 04 '14 at 16:49
  • I understand generics in a C++ point of view. Could you give me an example on how this can be achieved with generics without the usual if-else typeof statements? – joe.ds Jun 04 '14 at 16:59
  • 1
    Is it necessary that you use an interface pattern? If not look [here](https://dotnetfiddle.net/FuSN6r) – Antarr Byrd Jun 04 '14 at 17:01
  • What is the difference between `PrintColor` and `CatchColor`? Why do you need `CatchColor` in every subclass? – keenthinker Jun 04 '14 at 17:26
  • Sorry for the confusion. I removed 'PrintColor' entirely from the exmaple to show my problem. – joe.ds Jun 04 '14 at 17:28
  • 1
    It is still not so clear for me ... why do you need to catch `blue` in `green`? – keenthinker Jun 04 '14 at 17:30
  • in your `PassColor(IColor c)` you say that wait `IColor` so when you pass clas that implement this interface will be call implementation this interface function from derived class – Grundy Jun 04 '14 at 17:34
  • 2
    Two cents -- It seems you have an interface that has a method that does not care about differences. You have one implementation of the interface that also does not care about the difference, while you have one that does. Since there is this inconsistency, I suggest the straightforward approach is to have the implementation that cares be the one to figure it out. Type-checking is not ideal, but sometimes it's the right tool. If all implementations cared, then the interface should, too, and you might consider the *Visitor Pattern*, but based on your sample code, I'm not certain it's applicable. – Anthony Pegram Jun 04 '14 at 17:39
  • Maybe it will be easier to understand the problem if you give an example with more colors and describe the expected result, something like: 1 green object, 1 blue object, 1 purple object and they are passed to the `CatchColor` method of the `ColorManager` class - `cm.CatchColor(green); cm.CatchColor(purple);`. – keenthinker Jun 04 '14 at 17:43
  • Thank you all for the help. Anthony Pegram, the Visitor Pattern lead me to the c# dynamic keyword, which is exactly what I needed. – joe.ds Jun 04 '14 at 17:51
  • Please note that the methods in the `GreenColor` class `CatchColor(BlueColor c)` and `CatchColor(IColor c)` will never be called with your current implementation. – keenthinker Jun 04 '14 at 18:00

3 Answers3

2

One possiblity to tell the ColorManager class to use the correct type of the passed object is to use an abstract class, that already implements the CatchColor:

public abstract class IColor 
{
    // override in every class
    public abstract void PrintColor();
    // has the correct type passed with the interface
    public void CatchColor(IColor c)
    {
        c.PrintColor();
    }
}

Then the sub classes need to implement only PrintColor with the correct color:

public class BlueColor : IColor
{
    public override void PrintColor()
    {
        Console.WriteLine("BLUE!");
    }
}

public class GreenColor : IColor
{
    public override void PrintColor()
    {
        Console.WriteLine("GREEN!");
    }
}

The manager is the same:

public class ColorManager
{
    public void PassColor(IColor c)
    {
        c.CatchColor(c);
    }
}

It can be used like this:

GreenColor G = new GreenColor();
var cm = new ColorManager();
cm.PassColor(G);
cm.PassColor(new BlueColor());

The outputs is:

GREEN!
BLUE!
keenthinker
  • 7,645
  • 2
  • 35
  • 45
1

What you want is late method binding.

The downside to this is you have to add methods for each new type of color. The upside is you don't have to maintain a case statement or conditional logic.

See here for more detail: Early and late binding

Edit: Here is a working example of this type of late-binding.

class Program {

    static void Main(string[] args) {

        //Declare instances
        BaseClass myClass = new Class2();
        BaseClass otherClass = new Class1();

        //Invoke the action method which will match based on the BaseClass type
        Action(myClass);
        Action(otherClass);

        Console.ReadLine();
    }

    public static void Action(BaseClass classType) {
        //Remove the compile-time type so the runtime can select the method based on signature
        dynamic aClass = classType;
        ServiceMethod(aClass);

    }

    public static void ServiceMethod(dynamic input) {
        Methods(input);
    }

    public static void Methods(Class1 classType) {
        Console.WriteLine("Class1");
        Debug.WriteLine("Class1");
    }

    public static void Methods(Class2 classtype) {
        Console.WriteLine("Class2");
        Debug.WriteLine("Class2");
    }

    public static void Methods(Class3 classType) {
        Console.WriteLine("Class3");
        Debug.WriteLine("Class3");
    }

}

public abstract class BaseClass { //This could also be an interface

    public Guid Id { get; set; }
    public string Name { get; set; }
}

public class Class1 : BaseClass {

}

public class Class2 : BaseClass{
}

public class Class3 : BaseClass {
}
Community
  • 1
  • 1
xDaevax
  • 2,012
  • 2
  • 25
  • 36
0

So you want something like:

    public void CatchColor(Color c)
    {
        if (c is BlueColor)
            CatchColor(c as BlueColor);
        if (c is GreenColor)
            CatchColor(c as GreenColor);
    }

?

Jonathan Nixon
  • 4,940
  • 5
  • 39
  • 53
nl-x
  • 11,762
  • 7
  • 33
  • 61