Home > Back-end >  c# generic with supplied parameter names
c# generic with supplied parameter names

Time:01-22

I'm trying to create a generic function that can take a list of objects with start-datetime and end-datetime and combine them if they're right after one another with no gaps between.

        public static IEnumerable<T> MakeBlocks<T>(IEnumerable<T> input)
        {
            List<T> outList = new List<T>();
            if (input.Count() == 0) return outList;

            T thisEntry = input.First();
            foreach (var nextEntry in input.Skip(1))
            {
                if ( nextEntry != null && nextEntry.StartDT == thisEntry.EndDT)
                {
                    thisEntry.EndDT = nextEntry.EndDT;
                }
                else
                {
                    outList.Add(thisEntry);
                    thisEntry = nextEntry;
                }
            }
            outList.Add(thisEntry);

            return outList;
        }

This works fine if I know what the "From" and "to" property is called, but how can I do this with a generic?

The "unknown" properties in the above pseudo-example are called StartDT and EndDT, but they could be called anything.

In JavaScript I can just supply the the property name as a string, but that won't do in c#.

Is this possible and how?

CodePudding user response:

You can use generic constraints. So you would have a class that all your T's inherit from. Like so:

Modified method to use generic constarint

public static IEnumerable<T> MakeBlocks<T>(IEnumerable<T> input) where T : SomeClass
{
    List<T> outList = new List<T>();
    if (input.Count() == 0) return outList;

    T thisEntry = input.First();
    foreach (var nextEntry in input.Skip(1))
    {
        if (nextEntry != null && nextEntry.StartDT == thisEntry.EndDT)
        {
            thisEntry.EndDT = nextEntry.EndDT;
        }
        else
        {
            outList.Add(thisEntry);
            thisEntry = nextEntry;
        }
    }
    outList.Add(thisEntry);

    return outList;
}

Base class that all your T's should inherit from

public abstract class SomeClass
{
    public DateTime EndDT { get; set; }
    public DateTime StartDT { get; set; }
}

CodePudding user response:

This is possible, if you pass Getter and Setter functions:

    public static IEnumerable<T> MakeBlocks<T>(IEnumerable<T> input, 
       Func<T, DateTime> getStartProperty, 
       Func<T, DateTime> getEndProperty, 
       Action<T, DateTime> setEndProperty) {

        List<T> outList = new List<T>();
        if (!input.Any()) return outList;
    
        T thisEntry = input.First();
        foreach (var nextEntry in input.Skip(1))
        {
            if ( nextEntry != null && getStartProperty(nextEntry) == getEndProperty(thisEntry))
            {
                setEndProperty(thisEntry, getEndProperty(nextEntry));
            }
            else
            {
                outList.Add(thisEntry);
                thisEntry = nextEntry;
            }
        }
        outList.Add(thisEntry);

        return outList;
        
    }

So you'd invoke it with some lambda functions:

var result = MakeBlocks<MyClass>(
    myCollection, 
    mc => mc.StartDate, 
    mc => mc.EndDate, 
    (mc, value) => mc.EndDate = value
);
  • Related