Home > Software design >  How to make a re-usable method of type T
How to make a re-usable method of type T

Time:02-25

I have a method as below

List<Customer> GetCusts = dataContext.Customers;

The customers table has a field called IsValued so i can do something like this

foreach (var c in GetCusts)
{
  if(c.IsValued)
    {
     // do something
    }
}

I have a products table doing the exact same thing also with the same column name

List<Product> GetProds = dataContext.Products;

foreach (var p in GetProds)
{
  if(p.IsValued)
    {
     // do something
    }
}

I thought to turn this into a Generic method (or better a class), so i can pass in a generic list a bit like

foreach (var p in GetData) // GetData could be a List<t> but of course i cant cast it. 
{
  if (p.IsValued)
     {}
}

but of course IsValued does not exist. I know the reason why (due to it being a generic type) but after researching around to see if its possible i couldnt get a decent example and test it out or maybe i just didnt understand. Can anyone advise how this could be possible or lead me to an article to achieve this?

Edit 1

My attempt so far in a class, it could be wrong but to give an idea in case im on the wrong path. I assume i need a property of IsValued (which doesnt have to be of a bool value) in the GenericValue class?

public interface ICustomGenerics<T>
{
    IEnumerable<T> GetData();
}

public class GenericValue<T> : ICustomGenerics<T> where T : class
{
    public IEnumerable<T> GetAll()
    {
        _entities.
    }
}

CodePudding user response:

Here is how you can use an interface:

public interface IValued {
    bool IsValued { get; set; }
}

public class Customer : IValued {
    public bool IsValued { get; set; }
}

public class Product : IValued {
    public bool IsValued { get; set; }
}

public void filterData<T>(List<T> data) where T: IValued {
    foreach (var d in data) {
        if (d.IsValued) {
        }
    }

}

CodePudding user response:

As others pointed out you can either pick a base class and derive from that, or you can use an interface. I'd rather go with the interface in this case.

Assuming you are using Entity Framework, you can use a partial classes to apply your interface:

public interface IValuable
{
    bool IsValued { get; set; } 
}

and you'd have partial classes like:

public partial class Customer : IValuable
{
   // IValuable implementation
   public bool IsValued { get; set; }
}
public partial class Product : IValuable
{
   // IValuable implementation
   public bool IsValued { get; set; }
}

Now you can have a processor / service class that accepts these as generics with a condition that they should all implement this interface:

public class Processor<T> where T : IValuable
{
    public Something Process(T parameter)
    {
         foreach (var p in GetData) 
         {
            if (p.IsValued)
            {
                // Do stuff
            }
         }
    }
}

Since you declared your generic to have IValuable implementation, the code below will know IsValuable is a member.

I suggest this approach over base classes because interfaces are best used this way to define common behaviour. You can even see the same pattern in the framework, IDisposable (which implements Dispose()) and IEnumerable / IEnumerator (which implements things like GetEnumerator(), MoveNext() etc) are two most common examples.

  • Related