You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持自定义起止时间属性名的C#泛型合并函数?

实现适配任意起止属性名的C#泛型时间块合并函数

问题背景

现有泛型函数MakeBlocks依赖固定的StartDT和EndDT属性名实现时间连续项合并,需要修改为支持任意命名的起止时间属性,适配不同的数据结构。

解决方案

C#作为强类型语言,虽然不能直接像JavaScript那样传入属性名字符串,但可以通过委托(Func/Action)实现类型安全的属性访问逻辑,或者通过反射实现字符串指定属性的方式,以下是两种可行方案:


方案1:使用委托(推荐,类型安全+高性能)

通过传递获取起始时间、获取结束时间、设置结束时间的委托,让函数适配任意属性名,编译时即可检查属性是否存在,避免运行时错误。

修改后的泛型函数:

using System;
using System.Collections.Generic;
using System.Linq;

public static class TimeBlockMerger
{
    public static IEnumerable<T> MakeBlocks<T>(
        IEnumerable<T> input,
        Func<T, DateTime> getStartTime,
        Func<T, DateTime> getEndTime,
        Action<T, DateTime> setEndTime)
    {
        var outList = new List<T>();
        if (!input.Any())
            return outList;

        T currentEntry = input.First();
        foreach (var nextEntry in input.Skip(1))
        {
            if (nextEntry != null && getStartTime(nextEntry) == getEndTime(currentEntry))
            {
                // 合并时间块:更新当前项的结束时间为下一项的结束时间
                setEndTime(currentEntry, getEndTime(nextEntry));
            }
            else
            {
                outList.Add(currentEntry);
                currentEntry = nextEntry;
            }
        }
        outList.Add(currentEntry);
        return outList;
    }
}

调用示例:
假设我们有一个自定义的Meeting类:

public class Meeting
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    // 其他属性...
}

调用合并函数时,只需传入对应属性的委托:

List<Meeting> meetings = GetMeetings(); // 获取会议列表
var mergedMeetings = TimeBlockMerger.MakeBlocks(
    meetings,
    m => m.Start,       // 获取起始时间的委托
    m => m.End,         // 获取结束时间的委托
    (m, newEnd) => m.End = newEnd // 设置结束时间的委托
);

方案2:使用反射(适配字符串指定属性名)

如果需要类似JavaScript那样通过字符串指定属性名,可以借助反射实现,但此方案编译时无法检查属性是否存在,性能略低于委托方案,适合非高频调用场景。

修改后的泛型函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public static class TimeBlockMerger
{
    public static IEnumerable<T> MakeBlocks<T>(
        IEnumerable<T> input,
        string startPropName,
        string endPropName)
    {
        var outList = new List<T>();
        if (!input.Any())
            return outList;

        // 获取属性信息
        PropertyInfo startProp = typeof(T).GetProperty(startPropName);
        PropertyInfo endProp = typeof(T).GetProperty(endPropName);

        if (startProp == null)
            throw new ArgumentException($"类型 {typeof(T).Name} 不存在属性 {startPropName}");
        if (endProp == null)
            throw new ArgumentException($"类型 {typeof(T).Name} 不存在属性 {endPropName}");
        if (startProp.PropertyType != typeof(DateTime) || endProp.PropertyType != typeof(DateTime))
            throw new ArgumentException("起止属性必须为DateTime类型");

        T currentEntry = input.First();
        foreach (var nextEntry in input.Skip(1))
        {
            if (nextEntry != null)
            {
                DateTime currentEnd = (DateTime)endProp.GetValue(currentEntry);
                DateTime nextStart = (DateTime)startProp.GetValue(nextEntry);

                if (nextStart == currentEnd)
                {
                    DateTime nextEnd = (DateTime)endProp.GetValue(nextEntry);
                    endProp.SetValue(currentEntry, nextEnd);
                }
                else
                {
                    outList.Add(currentEntry);
                    currentEntry = nextEntry;
                }
            }
            else
            {
                outList.Add(currentEntry);
                currentEntry = nextEntry;
            }
        }
        outList.Add(currentEntry);
        return outList;
    }
}

调用示例:

List<Meeting> meetings = GetMeetings();
var mergedMeetings = TimeBlockMerger.MakeBlocks(meetings, "Start", "End");

注意事项

  1. 两种方案都要求输入列表已经按起始时间排序,否则合并逻辑会失效;
  2. 委托方案优先推荐,兼顾类型安全和性能;
  3. 反射方案需注意处理属性不存在、类型不匹配的异常情况。

内容的提问来源于stack exchange,提问作者Henrik Clausen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:15:31