C# 多列上不区分大小写的组

C# 多列上不区分大小写的组,c#,linq,linq-to-sql,C#,Linq,Linq To Sql,是否仍然可以执行类似于以下内容的LINQ2SQL查询: var result = source.GroupBy(a => new { a.Column1, a.Column2 }); 或 但是忽略分组列内容的大小写?可以将StringComparer.InvariantCultureInogoreCase传递给GroupBy扩展方法 var result = source.GroupBy(a => new { a.Column1, a.Column2 },

是否仍然可以执行类似于以下内容的LINQ2SQL查询:

var result = source.GroupBy(a => new { a.Column1, a.Column2 });


但是忽略分组列内容的大小写?

可以将
StringComparer.InvariantCultureInogoreCase
传递给
GroupBy
扩展方法

var result = source.GroupBy(a => new { a.Column1, a.Column2 }, 
                StringComparer.InvariantCultureIgnoreCase);

或者,您也可以按照评论中的建议,在每个字段上使用
toupper
。我推荐
ToUpperInvariant
ToUpper
而不是
ToLower
ToLowerInvariant
,因为它是为编程比较目的而优化的。

我无法让NaveenBhat的解决方案工作,出现编译错误:

方法的类型参数 'System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)“”不能为空 从用法推断。尝试显式指定类型参数

为了使它能够工作,我发现定义一个新类来存储我的键列(GroupKey),然后定义一个实现IEqualityComparer(KeyComparer)的单独类是最简单和最清晰的。然后我可以打电话

var result= source.GroupBy(r => new GroupKey(r), new KeyComparer());
KeyComparer类将字符串与InvariantCultureInogoreCase比较器进行比较,因此NaveenBhat为我指出了正确的方向,这是值得称赞的

我的课程的简化版本:

private class GroupKey
{
    public string Column1{ get; set; }
    public string Column2{ get; set; }

    public GroupKey(SourceObject r) {
        this.Column1 = r.Column1;
        this.Column2 = r.Column2;
    }
}

private class KeyComparer: IEqualityComparer<GroupKey>
{

    bool IEqualityComparer<GroupKey>.Equals(GroupKey x, GroupKey y)
    {
        if (!x.Column1.Equals(y.Column1,StringComparer.InvariantCultureIgnoreCase) return false;
        if (!x.Column2.Equals(y.Column2,StringComparer.InvariantCultureIgnoreCase) return false;
        return true;
        //my actual code is more complex than this, more columns to compare
        //and handles null strings, but you get the idea.
    }

    int IEqualityComparer<GroupKey>.GetHashCode(GroupKey obj)
    {
        return 0.GetHashCode() ; // forces calling Equals
        //Note, it would be more efficient to do something like
        //string hcode = Column1.ToLower() + Column2.ToLower();
        //return hcode.GetHashCode();
        //but my object is more complex than this simplified example

    }
}
私有类组密钥
{
公共字符串Column1{get;set;}
公共字符串Column2{get;set;}
公共组密钥(SourceObject r){
this.Column1=r.Column1;
this.Column2=r.Column2;
}
}
私有类密钥比较器:IEqualityComparer
{
bool IEqualityComparer.Equals(组键x、组键y)
{
如果(!x.Column1.Equals(y.Column1,StringComparer.InvariantCultureInogoreCase)返回false;
如果(!x.Column2.Equals)(y.Column2,StringComparer.InvariantCultureInogoreCase)返回false;
返回true;
//我的实际代码比这更复杂,需要比较的列更多
//和处理空字符串,但你明白了。
}
int IEqualityComparer.GetHashCode(GroupKey obj)
{
返回0.GetHashCode();//强制调用等于
//注意,这样做会更有效率
//字符串hcode=Column1.ToLower()+Column2.ToLower();
//返回hcode.GetHashCode();
//但我的目标比这个简化的例子更复杂
}
}

我也遇到了同样的问题,即通过表中DataRow对象的值进行分组,但我只是在DataRow对象上使用.ToString()来解决编译器问题,例如

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"].ToString(),
    StringComparer.InvariantCultureIgnoreCase)
而不是

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"],
    StringComparer.InvariantCultureIgnoreCase)

我对Bill B的答案进行了扩展,使事情变得更加动态,以避免对
GroupKey
IQualityComparer
中的列属性进行“硬编码”


这样,您可以将任意数量的列传递到
GroupKey
构造函数中。

这不起作用吗?
a=>{Column1=a.Column1.ToLower(),Column2=a.Column2.ToLower()}
您确定您没有只键入
StringComparison.InvariantCultureIgnoreCase
(这是一个枚举)而不是
StringComparer.InvariantCultureIgnoreCase
(这是一个类)?您是对的,@dav_i,这是“无法从'System.stringComparation'转换…”的来源收到错误。但是,即使我没有犯那个错误,也会抛出一个不同的编译错误。我已经更新了我的答案,以反映遇到的问题和此解决方案的基本原理。谢谢!a
StringComparer
无法比较匿名类型的实例,只能比较字符串。需要一个新的比较器实现(请参阅Bill B的答案)@fubo这是一个错误的解决方案,因为“Column1”和“Column2”在连接时产生与“Colu”和“mn1Column2”相同的键值。无法查看多个列的位置。
MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"],
    StringComparer.InvariantCultureIgnoreCase)
private class GroupKey
    {
        public List<string> Columns { get; } = new List<string>();

        public GroupKey(params string[] columns)
        {
            foreach (var column in columns)
            {
                // Using 'ToUpperInvariant()' if user calls Distinct() after 
                // the grouping, matching strings with a different case will 
                // be dropped and not duplicated
                Columns.Add(column.ToUpperInvariant());
            }
        }

    }

    private class KeyComparer : IEqualityComparer<GroupKey>
    {

        bool IEqualityComparer<GroupKey>.Equals(GroupKey x, GroupKey y)
        {
            for (var i = 0; i < x.Columns.Count; i++)
            {
                if (!x.Columns[i].Equals(y.Columns[i], StringComparison.OrdinalIgnoreCase)) return false;
            }

            return true;
        }

        int IEqualityComparer<GroupKey>.GetHashCode(GroupKey obj)
        {
            var hashcode = obj.Columns[0].GetHashCode();

            for (var i = 1; i < obj.Columns.Count; i++)
            {
                var column = obj.Columns[i];
                // *397 is normally generated by ReSharper to create more unique values
                // So I added it here, it's technically not required
                hashcode = (hashcode * 397) ^ (column != null ? column.GetHashCode() : 0);
            }

            return hashcode;
        }
    }
var result = source.GroupBy(r => new GroupKey(r.Column1, r.Column2, r.Column3), new KeyComparer());