plee
plee

Reputation: 11

Using an input class as a method output

I'm trying to pass in a dynamic model class to a more generic class. Part of the generic class is using dapper querying to a typed List. I'm trying to make this generic class modular in that in can take in any model class and be able to use this model class as an output of the query.

Am I even approaching this problem in the right way?

So in the example below, I'd like for the GetFruits method to be dynamic in that it would return List<Bananas> if Bananas is passed in or List<Orange> if Oranges is passed in

class FruitBasket
{
    public FruitBasket(dynamic ModelClass)
    {

    }

    public List<Orange> GetFruits(connection)
    {
        List<Orange> oranges = connection.Query<Orange>("Select * from Oranges"); 
        return oranges
    }
}

//Passes in Oranges model class
var fruits = new FruitBasket(new Oranges())

//Passes in Bananas model class
var fruits = new FruitBasket(new Bananas ())

Upvotes: 1

Views: 86

Answers (4)

Kenneth
Kenneth

Reputation: 28737

You can either make the class generic or you can make the method generic. Either way, you need a base class for your different fruits:

public class Fruit { }

public class Orange : Fruit { }

public class Banana : Fruit { }

Generic class approach:

public class FruitBasket<T> Where T : Fruit  // FruitBasket of something where something must be a fruit 
{
    public List<T> GetFruits(connection)
    {
        var fruitType = typeof(T);

        if (fruitType == typeof(Banana))
            return connection.Query<Banana>("Select * from Bananas");
        else if (fruitType == typeof(Orange))
            return connection.Query<Orange>("Select * from Oranges");
    }
}

var orangeBasket = new FruitBasket<Orange>();
var oranges = orangeBasket.GetFruits(connection);

var bananaBasket = new FruitBasket<Banana>();
var bananas = bananaBasket.GetFruits(connection);

Generic method approach:

public class FruitBasket
{
    public List<T> GetFruits<T>(connection Where T : Fruit  // Get list of something where something must be a fruit 
    {
        var fruitType = typeof(T);

        if (fruitType == typeof(Banana))
            return connection.Query<Banana>("Select * from Bananas");
        else if (fruitType == typeof(Orange))
            return connection.Query<Orange>("Select * from Oranges");
    }
}

var fruitBasket= new FruitBasket();
var oranges = fruitBasket.GetFruits<Orange>(connection);
var bananas = fruitBasket.GetFruits<Banana>(connection);

Which approach you choose depends on your use case. Can a fruit basket only contain one type of fruit? => generic class Can a fruit basket contain multiple types of fruit? => generic method

Upvotes: 0

Yazan Ati
Yazan Ati

Reputation: 41

Here is how GetFruits should look like

public List<Fruit> GetFruits(connection)
{

    if (FruitBasket.CurrentFruit is Banana))
    {
        var bananas = connection.Query<Banana>("Select * from Bananas");
        return bananas;
    }
    else if (FruitBasket.CurrentFruit is Orange)
    {
        var oranges = connection.Query<Orange>("Select * from Oranges");
        return oranges;
    }

    //You may replace this exception by returning null or an empty list
    throw new Exception("Not supported fruit type");
}

Another solution would be instead of using dynamic you may use fruite as a base class (or abstract class) for both orange and banana

Upvotes: 0

brnlmrry
brnlmrry

Reputation: 421

To accomplish your specific, literal request, I would approach this not with dynamic, but with an IFruit interface containing a GetFruits method. Make your repository/list class accept a generic that must support that interface. Then it's just a matter of new MyRepoList<Banana>. I would abandon dynamic entirely as soon as possible - in my experience the short-term benefits never outweigh the long-term problems.

Generally - it sounds like you're working on a generic, simple repository. A general limitation of this approach (one entity per repository) is that at some point you're going to want to update multiple entities in one transaction. I would strongly encourage you to design your repositories around the units of work that your application actually performs, rather than trying to simplify/generalize how your entities are stored. It's far too easy to make your business logic awkward/difficult because you create the repositories first.

Upvotes: 0

Sach
Sach

Reputation: 10393

I'm guessing Banana and Orange are subclasses of Fruit. So are you looking for something like this:

public class FruitBasket
{
    public Fruit CurrentFruit { get; set; }

    public FruitBasket(Fruit fruit)
    {
        CurrentFruit = fruit;
    }

    public List<Fruit> GetFruits(connection)
    {
        var fruitType = CurrentFruit.GetType();

        if (fruitType == typeof(Banana))
        {
            var bananas = connection.Query<Banana>("Select * from Bananas");
            return bananas;
        }
        else if (fruitType == typeof(Orange))
        {
            var oranges = connection.Query<Orange>("Select * from Oranges");
            return oranges;
        }
    }
}

public class Fruit { }

public class Orange : Fruit { }

public class Banana : Fruit { }

Upvotes: 1

Related Questions