Allen Zhang
Allen Zhang

Reputation: 2552

C# how to make a function that can return either child or parent class

Not sure if I made it clear on the title. What I want is this:
There is a parent class:

public class parent  
....  

And a child class:

public class child : parent  
....  

Now I need a method that can return either:

List<(what goes here?)> GetSomeValue(string id, boolean needChild) {  
  ......  
  if (needChild)  
    return BuildChildResult(id);  
  else  
    return BuildParentResult(id);  
}  

Is this something possible to do?
What should be in the bracket?

Upvotes: 0

Views: 2887

Answers (5)

ConditionRacer
ConditionRacer

Reputation: 4498

This should do it

IEnumerable<parent> GetSomeValue(string id, boolean needChild) {  
  ......  
  if (needChild)  
    return BuildChildResult(id);  
  else  
    return BuildParentResult(id);  
}  

Upvotes: 0

Tien Dinh
Tien Dinh

Reputation: 1038

You can use Generic as follows

    public static List<T> GetSomeValue<T>(string id)
    {
        return (typeof(T) == typeof(Child)) ? BuildChildResult(id) as List<T> : BuildParentResult(id) as List<T>;
    }

Then you can call it like

        var childList = GetSomeValue<Child>("");
        var parentList = GetSomeValue<Parent>("");

Upvotes: 0

Icemanind
Icemanind

Reputation: 48696

I think an interface is the way to go. Look at this program:

class Program
{
    static void Main(string[] args)  
    {
        bool needChild = true;

        IEnumerable<IMyClass> myChildList = GetSomeValue("1", needChild);
        List<Child> myChildren = myChildList.Cast<Child>().ToList();

        needChild = false;
        IEnumerable<IMyClass> myParentList = GetSomeValue("1", needChild);
        List<Parent> myParents = myParentList.Cast<Parent>().ToList();

    }

    private static IEnumerable<IMyClass> GetSomeValue(string id, bool needChild)
    {
        if (needChild)
        {
            return BuildChildResult(id);
        }

        return BuildParentResult(id);
    }

    private static IEnumerable<IMyClass> BuildChildResult(string id)
    {
        var list = new List<IMyClass>
        {
            new Child {ChildName = "Test 1", Id = "1"},
            new Child {ChildName = "Test 2", Id = "1"},
            new Child {ChildName = "Test 3", Id = "1"},
            new Child {ChildName = "Test 4", Id = "2"},
            new Child {ChildName = "Test 4", Id = "2"},
            new Child {ChildName = "Test 4", Id = "3"}
        };

        return list.Where(z => z.Id == id).ToList();
    }

    private static IEnumerable<IMyClass> BuildParentResult(string id)
    {
        var list = new List<IMyClass>
        {
            new Parent {ParentName = "Test 1", Id = "1"},
            new Parent {ParentName = "Test 2", Id = "1"},
            new Parent {ParentName = "Test 3", Id = "1"},
            new Parent {ParentName = "Test 4", Id = "2"},
            new Parent {ParentName = "Test 4", Id = "2"},
            new Parent {ParentName = "Test 4", Id = "3"}
        };

        return list.Where(z => z.Id == id).ToList();
    }
}

public interface IMyClass
{
    string Id { get; set; }
    bool IsParent { get; set; }
}

public class Parent : IMyClass
{
    public string Id { get; set; }
    public bool IsParent { get; set; }
    public string ParentName { get; set; }

    public Parent()
    {
        IsParent = true;
    }
}

public class Child : IMyClass
{
    public string Id { get; set; }
    public bool IsParent { get; set; }
    public string ChildName { get; set; }

    public Child()
    {
        IsParent = false;
    }
}

Running this will create a child list called myChildren and a parent list called myParents.

The interface only needs one property, the bool IsParent property. Through that, the GetSomeValue method can build the appropriate parent or child, then return an enumerated list, which can then be cast to the appropriate type.

Upvotes: 0

DevEstacion
DevEstacion

Reputation: 1977

Returning different types of List<T> wont work since List is not Covariant.

You can achieve your goal by lowering your response to the Interface level that implements the out generic modifier which is the IEnumerable<T>

So in this example code mockup, it should work.

private static IEnumerable<Parent> Test(bool flag) // returns a covariant collection
{
    if (flag)
        return new List<Parent>(); 
    else
        return new List<Child>();
} 

Read more about Covariance and Contravariance

Upvotes: 6

TGH
TGH

Reputation: 39258

You can add an interface to the classes and have your method return an interface instead of a concrete type.

However I would point out that since this is either a child or a parent, and no other logic, I would consider making it two methods to avoid the casting. It may seem like it saves code to wrap it in a single method, but keep on mind that the complexity of casting/branching is then pushed out to the caller.

Upvotes: 0

Related Questions