try
            {
                string path = _hostingEnvironment.ContentRootPath + @"\file\";
                HSSFWorkbook book = new HSSFWorkbook();
                ISheet s1 = book.CreateSheet("Gas领料单");
                IRow r1 = s1.CreateRow(0);
                string[] fieldInfies = { "GasName", "安全量", "抄表值", "partNo", "领料数量" };
                //给工作簿添加表头,设置表头样式及列宽
                for (int k = 0; k < fieldInfies.Length; k++)
                {
                    r1.CreateCell(k).SetCellValue(fieldInfies[k]);
                    //给每列设置样式
                    //r1.GetCell(k).CellStyle = CellStyle_Title;
                    //给每列设置列宽
                    s1.SetColumnWidth(k, 20 * 256);
                }
                
                for (int i = 0; i < ems.Count; i++)
                {
                    NPOI.SS.UserModel.IRow rt = s1.CreateRow(i + 1);
                    rt.CreateCell(0).SetCellValue(ems[i].gasName);
                    rt.CreateCell(1).SetCellValue(ems[i].qtyNum);
                    rt.CreateCell(2).SetCellValue(ems[i].onNum);
                    rt.CreateCell(3).SetCellValue(ems[i].partNo);
                    rt.CreateCell(4).SetCellValue(ems[i].editNum);
                    
                }
                //判断gasName名称是否一样,如果一样,合并第0,1,2三列
                foreach (ExcelModel item in ems)
                {
                    //IndexOf 找到列表出现相同信息的下标,使用FirstOrDefault是为了找到第一次出现此数据的行号
                    int start = ems.IndexOf(ems.FirstOrDefault(x => x.gasName == item.gasName));
                    //同样的方式,通过LastOrDefault是为了找到第=最后一次出现此数据的行号
                    int end = ems.IndexOf(ems.LastOrDefault(x => x.gasName == item.gasName));
                    //然后使用NPOI合并的方式进行合并,因为本次我们都是出现在第一列(excel从0开始),所以后面两个参数都
                    //是0
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 0, 0));
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 1, 1));
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 2, 2));
                }
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                string filename = DateTime.Now.ToString("yyyyMMddhhmmssffff") + ".xls";
                FileStream stream = new FileStream(path + filename, FileMode.CreateNew);
                book.Write(stream);
                stream.Seek(0, SeekOrigin.Begin);
                book.Close();
                stream.Close();
                var response = new
                {
                    code = 20000,
                    msg = "生成成功,是否下载?",
                    success = true,
                    icon="success",
                    url= $"{Request.Scheme}://{Request.Host}{Request.PathBase}/file/"+ filename
                };
                return Ok(response);
            }
            catch (Exception ex)
            {
                ////
            }
主要合并代码为:
 //判断gasName名称是否一样,如果一样,合并第0,1,2三列
                foreach (ExcelModel item in ems)
                {
                    //IndexOf 找到列表出现相同信息的下标,使用FirstOrDefault是为了找到第一次出现此数据的行号
                    int start = ems.IndexOf(ems.FirstOrDefault(x => x.gasName == item.gasName));
                    //同样的方式,通过LastOrDefault是为了找到第=最后一次出现此数据的行号
                    int end = ems.IndexOf(ems.LastOrDefault(x => x.gasName == item.gasName));
                    //然后使用NPOI合并的方式进行合并,因为本次我们都是出现在第一列(excel从0开始),所以后面两个参数都
                    //是0
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 0, 0));
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 1, 1));
                    s1.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 2, 2));
                }
效果如下图:
