0

I want to replace switch statement with dynamic code so that I could pass dynamic type to generic class

This is the code that I have written, but as a new type is added I should add another case and it violates Open Closed Principle.

public ActionResult ManageData(ManageDataType manageDataType)
        {
            var result = new List<ManageDataCommon>();
            switch (manageDataType)
            {
                case ManageDataType.Shift:
                    result = new BaseData<Shift>().GetSharedData();
                    break;
                case ManageDataType.ShiftManager:
                    result = new BaseData<ShiftManager>().GetSharedData();
                    break;
            }
            return View(result);
        }

And the code in view is:

<a href="@Url.Action("ManageData", "BaseData",
                         new {manageDataType= ManageDataType.Shift })"

<a href="@Url.Action("ManageData", "BaseData",
                         new {manageDataType= ManageDataType.ShiftManager})"

I like to implement code like this:

public ActionResult ManageData(T genericType)
        {
            var result = new BaseData<genericType>().GetSharedData();
            return View(result);
        }
Hamid Noahdi
  • 1,585
  • 2
  • 11
  • 18
  • What happens when you try ManageData(T genericType) ? – Guillaume CR Sep 10 '19 at 16:32
  • 1
    Possible duplicate of [Pass An Instantiated System.Type as a Type Parameter for a Generic Class](https://stackoverflow.com/questions/266115/pass-an-instantiated-system-type-as-a-type-parameter-for-a-generic-class) – gunr2171 Sep 10 '19 at 16:32
  • Look into conditional to polymorphism. You can use an Enum with a Dictionary to map each type instead of using generics inside your controller. – user10728126 Sep 10 '19 at 16:59

2 Answers2

4

Correct would be:

public ActionResult ManageData<T>()
{
    var result = new BaseData<T>().GetSharedData();
    return View(result);
}

But your call is a controller method. While I don't know enough to say it's impossible, it's definitely not easy. Your client should not know anything about types in the controller. So generally speaking you are right and you could use the code above, but in this case, I'm afraid you have to stay with what you have. Generics are not meant to be used across boundaries like that.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
1

You can use this (this maynot compile)

internal class ManageDataTypeBuilder
{ 
public IEnumerable<IDataType> DataTypes{ get; set; }

public ManageDataTypeBuilder()
{
    // add all datatypes to DataTypes ienumerable here
}

public void BuildDataType(DataType type)
{
    var dataType = DataTypes.FirstOrDefault(b => b.Type == type);

    if(dataType == null)
    {
        throw new Exception("No Datatype set");
    }else{
        type.DoActivity();
    }
}
}

I would keep controllers light weight and have only logic for bad request, ok request etc. you can move all the “processing” to a service and check the results of the method in a service to give BadRequest, Ok response etc.

Example: Pseudocode

 var results = _service.GetResults();
  if (results == null)
      return Badrequest;
  else return Ok;

You can dependency inject the service as IService.

Gauravsa
  • 6,330
  • 2
  • 21
  • 30