C#字符串重复问题

时间:2009-08-05 14:18:16

标签: c# .net string visual-studio-2008 ado.net

我使用的是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", "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);
        }
    }

编辑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.

4 个答案:

答案 0 :(得分:6)

这取决于你所说的“相同”。

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

"\uff12\uff43\uff48"

这些是“2ch”的"full width"版本。

编辑:为了回应您的编辑,显然DataSet使用了不同的平等概念,而除非您提供任何具体的内容,Dictionary将使用序数比较(由字符串本身提供)。< / p>

编辑:我很确定问题是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));
    }
}

编辑:如果您将DataTable的{​​{1}}属性设置为true,我怀疑它的行为与CaseSensitive相同。

答案 1 :(得分:5)

你把字符串放在哪一行?在我看来,你正在创建空白行并插入其中的两行?

这样的东西?

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

答案 2 :(得分:5)

一开始你需要示例代码:

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

虽然仍然存在问题,至少是因为真正的原因

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

this._compareFlags = CompareOptions.IgnoreWidth 
                     CompareOptions.IgnoreKanaType | 
                     CompareOptions.IgnoreCase;

docs忽略宽度:

  

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

System.Globalization.CultureInfo.CurrentCulture.CompareInfo.Compare(
    "2ch", "2ch", System.Globalization.CompareOptions.IgnoreWidth);

返回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;
}

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

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

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();
    }
}

答案 3 :(得分:1)

看起来第二个字符串的编码不同。调试时,第二个字符串作为垃圾返回。如果我删除第二个字符串并在Visual Studio中输入“2 c h”,它可以正常工作。