简体   繁体   中英

Genericizing a method and a parameter to be passed

I'm trying to learn generics and implement it in the following code. I'm new to the concept so it may not be the best approach so I'm open to anything.

I have a method that takes a class and maps it to an object of a new class and returns:

 public OtherClass CreateNeed(long id, string name, int needTypeId)
    {
        var newDto = new OtherClass();
        newDto.Id = id;
        newDto.Name = name;
        newDto.NeedTypeId = needTypeId;

        return newDtoToAdd;
    }

And this is how I call it:

var needClass = new NeedClass();
var addedNeed = CreateNeed(needClass.id, needClass.name, needClass.needTypeId);

But sometimes, the object I need to map is of the same OtherClass... so i call like this..

var otherClass = new OtherClass();
var otherAddedNeed = CreateNeed(otherClass.id, otherClass.name, otherClass.needTypeId);

I'd like to pass it as a generic type so the CreateNeed method can handle both types...maybe something like this:

var needClass = new NeedClass();
var addedNeed = CreateNeed<NeedClass>(needClass);

var otherClass = new OtherClass();
var addedNeed = CreateNeed<OtherClass>(otherClass);

I find myself having this kind of issue often in my code and needing to pass in only parts of classes to modify, but return always returning the same type of object. I'm also trying to learn generics in general, so how do i modify the method and the subsequent call to be genericized?

There are few options. First of all, you don't need generic method at all to achieve this. Surely you can do this with generics, but not necessarily.

First option , you create an interface to match both of the class structures and let a non-generic method accept this interface as parameter.

//Implement this interface with your 2 classes
public interface IClass
{
   int Id {get;set;}
   //other fields here.
}

public interface OtherClass : IClass
{
   public int Id {get;set;}
   //other fields here.
}

public interface NeedClass : IClass
{
   public int Id {get;set;}
   //other fields here.
}

public OtherClass CreateNeed(IClass input)
 {
     var newDto = new OtherClass();
     newDto.Id = input.id;
     newDto.Name = input.name;
     newDto.NeedTypeId = input.needTypeId;    
     return newDtoToAdd;
  } 

  //example call 
  var newNeedClass = new NeedClass();
  //set all your properties here.
  newNeedClass.Id =1;
  var otherClassInstance = CreateNeed(newNeedClass );

second one , Make the parameter type as dynamic . I suggest against this approach though.

thrid one ,if you are keen to use generics, then

public OtherClass CreateNeed<T>(T inp) where T: IClass 
     {
         var newDto = new OtherClass();
         newDto.Id = inp.id;
         newDto.Name = inp.name;
         newDto.NeedTypeId = inp.needTypeId;        
         return newDtoToAdd;
      }

Then you can call this using following syntax

var newNeedClass = new NeedClass();
//set all your properties here.
newNeedClass.Id =1;
var otherClassInstance = CreateNeed(newNeedClass );

Lastly , you can also use mapping libraries like Automapper that makes mappings easier. But, yeah that creates dependency with third party framework.

A solution is to define an interface with the required properties:

public interface IConvertable
{
    int id { get; set; }
    string name { get; set; }
    //...
}

Implement the interface in all classes you want to convert into each other. The generic approach would be:

public static T CreateNeed<T>(IConvertable ToConvert) where T : IConvertable, new()
{
    T Need = new T();
    Need.id = ToConvert.id;
    Need.name = ToConvert.name;
    //...
    return Need;
}

Now its possible to convert all classes implementing the IConvertable interface to an other class implementing the IConvertable interface (Note that the constructor don´t allows any parameter using this implementation). Example of usage:

OtherClass OldObject = new OtherClass() { id = 1, name = "test" };
NeededClass NewObject = CreateNeed<NeededClass>(OldObject);

You can also create mapper class like this:

public class Mapper
{
    public static TOutput Map<TInput, TOutput>(TInput input, Action<TInput, TOutput> mapFunc) 
        where TOutput : class, new()
    {
        TOutput t = new TOutput();
        mapFunc(input, t);
        return t;
    }
}

and then use it for mapping between classes:

    NeedClass c = new NeedClass { Id = 1, Name = "Name" };
    OtherClass oc = Mapper.Map<NeedClass, OtherClass>(c, (input, output) =>
    {
        output.Id = input.Id;
        output.Name = input.Name;
    });

Then define default mapper functions to use it regularly and for the cases where you want to map partially do it in line with the Action<TInput, TOutput> .

To be clear for the real life scenario you don't want to create these kind of mappers but to use AutoMapper instead. Good luck.

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