Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return one of two possible objects of different types sharing a method

I have 2 classes:

public class Articles
{
    private string name;

    public Articles(string name)
    {
        this.name = name;
    }

    public void Output()
    {
        Console.WriteLine("The class is: " + this.GetType());
        Console.WriteLine("The name is: " + name);
    }
}

And

public class Questionnaire 
{
    private string name;

    public Questionnaire(string name)
    {
        this.name = name;
    }

    public void Output()
    {
        Console.WriteLine("The class is: " + this.GetType());
        Console.WriteLine("The name is: " + name);
    }
}

I want to write a method, that takes an integer (1 meaning Articles should be returned, 2 meaning Questionnaire) and a name.

This method must return an instance of one of those two classes:

public [What type??] Choose(int x, string name)
    {
        if (x == 1)
        {
           Articles art = new Articles(name);
           return art;
        }
        if (x == 2)
        {
            Questionnaire ques = new Questionnaire(name);
            return ques;
        }
    }

What return type should I use, so I can call Output() on the result?

like image 786
Sashko Chehotsky Avatar asked Jul 05 '13 14:07

Sashko Chehotsky


2 Answers

Why not have a base class that has Output defined. Then return the base.

public abstract class BaseType {
    public abstract void Output();
}

Both Articles and Questionaire should inherit this BaseType.

public class Articles : BaseType {
  // Output method here
}

public class Questionaire : BaseType {
 // Output method here
}

Then you can do:

public static BaseType Choose(int x, string name) 
{
    if (x == 1)
    {
       Articles art = new Articles(name);
       return art;
    }
    if (x == 2)
    {
        Questionnaire ques = new Questionnaire(name);
        return ques;
    }
}

You could also achieve this via an interface.

public interface IInterface {
    void Output();
}

public class Articles : IInterface {
  // Output method here
}

public class Questionaire : IInterface {
 // Output method here
}

You would then have to modify the Choose method to return IInterface rather than BaseType. Whichever you choose is up to you.

Note: even if you can't change original classes you can still use these approaches before resorting to dynamic by providing wrapper classes that implement the interface and either inherits original or forwards calls to corresponding method:

public class ArticlesProxy : Articles, IInterface 
{
  public ArticlesProxy(string name) : base(name){}

}

public class QuestionaireProxy : Questionaire, IInterface {
  Questionaire inner;
  public QuestionaireProxy(string name) {  inner = new Questionaire(name); }

  public void Output() { inner.Output();}

}
like image 124
Darren Avatar answered Nov 04 '22 11:11

Darren


How about something like this:

public interface IHasOutput
{
    void Output();
}

public class Articles : IHasOutput

public class Questionnaire : IHasOutput

and then:

public static IHasOutput Choose...

You can of course call your interface anything you'd like, other than IHasOutput, I just don't know what to call it. This is what interfaces are for. Two different concrete implementations that share a common interface. Now when you call it you can do this:

var entity = MyClass.Choose(1, "MyName");
entity.Output();

and it doesn't matter what concrete implementation is returned. You know it implements a common interface.

like image 44
Mike Perrenoud Avatar answered Nov 04 '22 10:11

Mike Perrenoud