keeehlan
keeehlan

Reputation: 8054

How to modify a method to be able to return multiple types instead of just `object`?

I have this method, and I'm convinced that it's the source of another issue I'm having. I believe it's because this method returns a type of object instead of one of the three concrete types it actually returns.

Here's the method:

public object GetData(TableType type)
{
    switch (type)
    {
        case TableType.Person:
            return new Domain.PersonList(_personRepository.Get());
        case TableType.Event:
            return new Domain.EventList(_eventRepository.Get());
        case TableType.User:
            return new Domain.UserList(_userRepository.Get());
    }

    return null;
}

How can I modify this method to return a type other than object?

Upvotes: 1

Views: 322

Answers (6)

John Jesus
John Jesus

Reputation: 2404

Here's a whole answer with a general solution for parameterized types for return value.

class Program
{
    public enum TableType
    {
        Person,
        Event,
        User
    }

    class Person
    {
        public string Name { get; set; }
        public Person(string name) { this.Name = name; }
    }
    class Event
    {
        public int EventType { get; set; }
        public Event(int eventType) { this.EventType = eventType; }
    }
    class User
    {
        public string UserName { get; set; }
        public User(string username) { this.UserName = username; }
    }

    public static T GetData<T>(TableType tableType)
    {
        switch (tableType)
        {
            case TableType.Person:
                Person person = new Person("John");
                return (T)Convert.ChangeType(person, typeof(T));
            case TableType.Event:
                Event evt = new Event(2);
                return (T)Convert.ChangeType(evt, typeof(T));
            case TableType.User:
                User user = new User("jjesus");
                return (T)Convert.ChangeType(user, typeof(T));
        }
        return default(T);
    }

    static void Main(string[] args)
    {
        Person person = GetData<Person>(TableType.Person);
        Console.WriteLine("Person.Name {0}", person.Name);

        Console.WriteLine("Hit any key to continue");
        Console.ReadKey();
    }
}

Upvotes: 0

Mark F
Mark F

Reputation: 176

You could use generics to get this done,

public T GetData<T>()
{
    if(typeof(T) == typeof(Domain.PersonList))
        return new Domain.PersonList(_personRepository.Get());
    else if (typeof(T) == typeof(Domain.EventList))
        return new Domain.EventList(_eventRepository.Get());
    else if (typeof(T) == typeof(Domain.UserList))
        return new Domain.UserList(_userRepository.Get());
    }

    return default(T);
}

Upvotes: 1

EtherDragon
EtherDragon

Reputation: 2698

Another possibility is to use Interfaces to guarantee that only one of your three types is returned.

public IDomainList GetData(TableType type)
{
    switch (type)
    {
        case TableType.Person:
            return new Domain.PersonList(_personRepository.Get());
        case TableType.Event:
            return new Domain.EventList(_eventRepository.Get());
        case TableType.User:
            return new Domain.UserList(_userRepository.Get());
    }

    return null;
}

So long as PersonList, EventList, and UserList all implement the IDomainList interface, then you are guaranteed to return on of those three types. Then in your implementation, you can determine what to do based on the specific type returned.

Upvotes: 1

philologon
philologon

Reputation: 2105

First, you must identify what is the "lowest common denominator" base class for the three kinds of repositories. If you do not have one, then you should create one. One way to do this would be

public abstract class repositoryBase
{
   public virtual IList<repositoryBase> Get() { }
}

Then each of the three classes woudl inherit from repositoryBase:

public personRepository : repositoryBase
{
   public override IList<personRepository> Get()
   {
      // code here to return the list
   }
}

Once you have refactored the class hierarchy in this way, then you don't even need the GetData method. Where you were calling GetData, you now just call someRepository.Get();

If you are already inheriting from something else and adding a Get method to the base class is not a good fit, you can do the same thing I describe here using an Interface. Either approach, base class or interface work equally well in this case and both are good OO practice.

Upvotes: 1

ThunderGr
ThunderGr

Reputation: 2367

You can create three GetData functions, that will get the type as a parameter and return the correct type.

public List<TableType.Person> GetData(TableType.Person type)
{
    return new Domain.PersonList(_personRepository.Get());
}

public List<TableType.Event> GetData(TableType.Event type)
{
     return new Domain.EventList(_eventRepository.Get());
}

public List<TableType.User> GetData(TableType.User type)
{
     return new Domain.UserList(_userRepository.Get());
}

The runtime will pick the correct overload according to the type of the parameter.

EDIT: I am assuming that the Domain.xxxxList functions return a list of the mentioned type in this example. It is not required, of course.

Upvotes: 0

Yosi Dahari
Yosi Dahari

Reputation: 6999

What you need is generics. This way the method will return the type according to type.

This method for example returns TService type:

private TService GetService<TService>(ServiceInfo serviceInfo)
    where TService : class, ICoordinationExecutionService
{
    var service = _executionServices.FirstOrDefault(
            x => x.ServiceInfo.InstanceInfo.InstanceId == serviceInfo.InstanceInfo.InstanceId
                && serviceInfo.ServiceTypeName.Equals(x.ServiceInfo.ServiceTypeName));

    if (service == null)
    {
        throw new Exception("invalid service ");
    }

    return _directory.GetService<TService>(service.ServiceInfo);
}

Upvotes: 2

Related Questions