简体   繁体   中英

Call method on parameter of generic type

I want to write a generic method that as input has a list of generic objects. I want to call a method on each of the list items.

What I'm trying to do is writing something like:

public void ResetPointProperties<T> (List<T> Points) 
{
    foreach (T point in Points)
    {
       point.Reset();
    }
}

How can I call Reset() on my list items?

You are almost there. However, what is missing is that as it stands, the compiler does not know whether/that each T has a reset() method. Therefore, you will have to add a constraint to the T parameter that requires T to implement an interface or inherit from a class that declares such a reset() method.

For instance, let's assume you somewhere have the following interface:

public interface IThing
{
    void reset();
}

Then, you could declare your above method as follows:

public void ResetPointProperties<T> (List<T> Points)
    where T : IThing

This enforces that any type passed to the T type parameter must implement IThing . In return, the compiler can guarantee that point in your method actually has a reset() method that you can invoke.

If your question is "How can I call Reset() on T " , then - to do it properly - you need to introduce a generic type constraint .

You can do so using an interface:

public interface IResettable
{
    void Reset();
}

And apply that:

public void ResetPointProperties<T> (List<T> Points)
    where T : IResettable

Now when you call the ResetPointProperties() method, you must do so with an argument of List<T> where T implements the interface IResettable . For example a Point class:

public class Point : IResettable
{
    public void Reset()
    {
        X = 0;
        Y = 0;
    }
}

Ok, let's have a look at all possible ways of getting it to work :

A. Generic constraints

public void ResetPointProperties<T> (List<T> Points) 
   where T : ISomeInterface // interface must contain .Reset method
{
    foreach (T point in Points)
       point.Reset();      
}

B. Type check and explicit convertion before calling method :

public void ResetPointProperties<T> (List<T> Points) 
{
    if(typeof(T) != typeof(Point)) return;

    foreach (T point in Points)
    {
        Point p = point as Point;
        p.Reset();      
    }
}

C. Via reflection :

public void ResetPointProperties<T> (List<T> Points) 
{
    if(typeof(T) != typeof(Point)) return;
    MethodInfo method = typeof(T).GetMethod("Reset");

    foreach (T point in Points)
    {
        t.Invoke(point, null);
    }
}

D. Using dynamic :

public void ResetPointProperties<T> (List<T> Points) 
{ 
    foreach (dynamic point in Points)
    {
        point.Reset();
    }
}

If it's possible the best solution is to use interface and generic constraints. Next would be casting and then doing something (for example in scenario when class is from some external dll and you dont have control over it). Reflection and dynamics are generally not recommended, as they're slow, and almost impossible to unit-test.

But sometimes using of reflection and dynamics may solve some considerable time with some complicated scenarios.

Imagine you have 40 models in database and 3 viewmodel for each of this 40 models and you want to map them in some method...

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