C#字符串重复问题

Geo*_*ge2 2 .net c# string ado.net visual-studio-2008

我使用的是VSTS 2008 + C#+ .Net 3.0.我有两个输入字符串,我认为它们是不同的.但是下面的C#代码认为它们是相同的,并抛出System.Data.ConstraintException,表示Column Name被限制为唯一,但值已经存在.有什么想法有什么不对?

这是我的代码和我的输入字符串,

我输入字符串的十六进制视图,

http://i30.tinypic.com/2anx2b.jpg

我的输入字符串的记事本视图,

http://i30.tinypic.com/2q03hn4.jpg

我的代码,

    static void Main(string[] args)
    {
        string[] buf = new string[] { "2ch", "???" };

        DataTable bulkInserTable = new DataTable("BulkTable");
        DataColumn column = null;
        DataRow row = null;

        column = new DataColumn();
        column.DataType = System.Type.GetType("System.String");
        column.ColumnName = "Name";
        column.ReadOnly = true;
        column.Unique = true;
        bulkInserTable.Columns.Add(column);

        foreach (string item in buf)
        {
            row = bulkInserTable.NewRow();
            row["Name"] = item;
            bulkInserTable.Rows.Add(row);
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑1:

我的困惑是,为什么C#Dictionary认为它们不同,但DataSet认为它们是相同的.任何使行为一致的解决方案?这是我的代码来证明C#Dictionary认为它们不同,返回buf数组有两个元素.

            Dictionary<string, bool> dic = new Dictionary<string, bool>();
            foreach (string s in buf)
            {
                dic[s] = true;
            }
            buf = new List<string>(dic.Keys).ToArray(); // we got two strings here, other than one, which proves Dictionary thinks the two strings are different.
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

这取决于你所说的"相同".

这两个字符串具有不同的Unicode值,但我怀疑在一些规范化规则下它们是相同的.只是为了让其他人可以轻松地重现它而不会出现剪切和粘贴问题,第二个字符串是:

"\uff12\uff43\uff48"
Run Code Online (Sandbox Code Playgroud)

这些是"2ch" 的"全宽"版本.

编辑:为了响应您的编辑,显然DataSet使用不同的相等概念,而除非您提供任何具体的,Dictionary将使用序数比较(由字符串本身提供).

编辑:我很确定问题是DataTable正在使用CompareOptions.IgnoreWidth:

using System;
using System.Data;
using System.Globalization;

class Test
{
    static void Main()
    { 
        string a = "2ch";
        string b = "\uff12\uff43\uff48";

        DataTable table = new DataTable();            
        CompareInfo ci = table.Locale.CompareInfo;

        // Prints 0, i.e. equal
        Console.WriteLine(ci.Compare(a, b, CompareOptions.IgnoreWidth));
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果你将DataTable's CaseSensitive属性设置为true,我怀疑它的行为与...相同Dictionary.

  • 在实践中,CaseSensitivity似乎控制的不仅仅是区分大小写 - 它控制是否忽略宽度,*和*是否忽略"假名"类型.不太理想,我意识到......不幸的是,我不知道创建一个忽略宽度和假名类型的`IEqualityComparer <string>`的方法. (2认同)

Rus*_*est 5

你把字符串放在哪一行?它看起来像你在创建空白行并插入其中的2行?

像这样的东西?

        foreach (string item in buf)
        {
            row = bulkInserTable.NewRow();
            row["Name"] = item;//Set the data<------------
            bulkInserTable.Rows.Add(row);
        }
Run Code Online (Sandbox Code Playgroud)


Shu*_*oUk 5

一开始你需要你的示例代码:

foreach (string item in buf)
{
    row = bulkInserTable.NewRow();
    row["Name"] = item;
    bulkInserTable.Rows.Add(row);
}
Run Code Online (Sandbox Code Playgroud)

虽然这至少仍然存在问题,但真正的原因

这样做的原因是,在创建数据表时,有效的默认比较选项是:

this._compareFlags = CompareOptions.IgnoreWidth 
                     CompareOptions.IgnoreKanaType | 
                     CompareOptions.IgnoreCase;
Run Code Online (Sandbox Code Playgroud)

文档忽略宽度:

表示字符串比较必须忽略字符宽度.例如,日文片假名字符可以写成全宽或半宽.如果选择此值,则写为全角的片假名字符被视为等于写为半宽的相同字符.

System.Globalization.CultureInfo.CurrentCulture.CompareInfo.Compare(
    "2ch", "???", System.Globalization.CompareOptions.IgnoreWidth);
Run Code Online (Sandbox Code Playgroud)

返回0,即相同

我强烈建议你确实考虑这些值相同或引起进一步混淆但是如果你真的想改变它:

//CaseSensitive property uses this under the hood
internal bool SetCaseSensitiveValue(
    bool isCaseSensitive, bool userSet, bool resetIndexes)
{
    if (!userSet && (
        this._caseSensitiveUserSet || (this._caseSensitive == isCaseSensitive)))
    {
        return false;
    }
    this._caseSensitive = isCaseSensitive;
    if (isCaseSensitive)
    {
        this._compareFlags = CompareOptions.None;
    }
    else
    {
        this._compareFlags = CompareOptions.IgnoreWidth | 
                             CompareOptions.IgnoreKanaType | 
                             CompareOptions.IgnoreCase;
    }
    if (resetIndexes)
    {
        this.ResetIndexes();
        foreach (Constraint constraint in this.Constraints)
        {
            constraint.CheckConstraint();
        }
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

因此,您可以忽略大小写并完全禁用复杂的比较选项.

如果要创建具有相同行为的Dictionary,请使用以下比较器:

public class DataTableIgnoreCaseComparer : IEqualityComparer<string>
{
    private readonly System.Globalization.CompareInfo ci =
        System.Globalization.CultureInfo.CurrentCulture.CompareInfo; 
    private const System.Globalization.CompareOptions options = 
        CompareOptions.IgnoreCase | 
        CompareOptions.IgnoreKanaType | 
        CompareOptions.IgnoreWidth;

    public DataTableIgnoreCaseComparer() {}

    public bool Equals(string a, string b)
    {
        return ci.Compare(a, b, options) == 0;
    }

    public int GetHashCode(string s)
    {
        return ci.GetSortKey(s, options).GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)