简体   繁体   中英

Resolving generic method parameters in C#

I have a method that is overloaded 3 times with the exact same functionality, the only change is one parameter which is a list of a concrete type.

private void _doWork(string name, List<TargetItem> members)
{
    foreach(var member in members)
    {
      _doExtraWork(member.TimeToWork);
    }
}

private void _doWork(string name, List<NonTargetItem> members)
{
    foreach(var member in members)
    {
      _doExtraWork(member.TimeToWork);
    }
}

Thing to know here is the 2 classes in the lists are coming from a WSDL definition. The operation in the iteration is on shared members as they derive from the same base class, however this inheritance is abstracted in the WSDL.

I have tried to do something like this -

private void _doWork<T>(string name, List<T> members)
{
    var commonList = new List<>(); /// what type should I use here?

    if(typeof (T) == typeof(TargetItem))
    {
      commonList = members; // assume equal to means copying members to commonList with type conversion
    }
    if(typeof (T) == typeof(NonTargetItem))
    {
      commonList = members;
    }
    foreach(var member in commonList)
    {
      _doExtraWork(member.TimeToWork);
    }
}

Is this the right way to approach the problem and refactor this common code, or am I missing something here?

you can do something like this

 private static void _doWork<T>(string name, T members) where T : IEnumerable
{
     foreach(var member in members)
    {
      _doExtraWork(member.TimeToWork);
    }
}

In your Calling Code

_doWork("sdfsd", new List<TargetItem>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItem>()); // here just as example I am passing new instance

As the List<T> is of type IEnumerable<T> which in turn is of type IEnumerable. You can add IEnumerable generic constaints in your generic functions. In this way, you do not have to do type checking in your generic functions.

If you want to implement single doExtraWork method then you need to have CommonType for both TargetItem and NonTargetItem. you can solve this using Adapter Pattern like below

Interface IItem
{
 int TimeToWorkAdapt {get;}
}

//Now create a wrapper class for TargetItem and NonTargetItem

Class TargetItemAdapt : TargetItem,IItem
{
   public int TimeToWorkAdapt 
       {
           get { base.TimeToWork;}    
       }
}

Class NonTargetItemAdapt : NonTargetItem,IItem
{
   public int TimeToWorkAdapt 
       {
           get { base.TimeToWork;}    
       }
}
 // write a generic function which wrap calls to your do extra work method but with generic constriants to interface
private static void _doExtraWork<T>(T members) where T : IItem
    {
          _doExtraWork(member.TimeToWorkAdapt);

    }
// In your Main program...now use our wrapper classes

_doWork("sdfsd", new List<TargetItemAdapt>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItemAdapt>()); // here just as example I am passing new instance

I chose to downcast from the caller

_doWork("Target", Object.TargetItems.ToList<BaseClass>());
_doWork("NonTarget", Object.NonTargetItems.ToList<BaseClass>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM