2009-08-05 80 views
2

我正在使用VSTS 2008 + C#+ .Net 3.0。我有兩個輸入字符串,我認爲它們是不同的。但是下面的C#代碼認爲它們是相同的,並拋出System.Data.ConstraintException,表示列名不是唯一的,但值已經存在。任何想法有什麼不對?C#字符串重複問題

這裏是我的代碼和我的輸入字符串,我輸入的字符串

十六進制查看,我的輸入字符串的

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#字典認爲它們是不同的,但數據集認爲它們是相同的。任何解決方案使行爲一致?這裏是我的代碼來證明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. 
+1

拉丁字符的「正常」和完整/半角形式通常被認爲是等價的,如果你正在處理文本。 – Joey 2009-08-05 14:23:17

+0

感謝Johannes,我想了解更多關於什麼意思是完整和半角形式的拉丁文,你能推薦一些讀物嗎? – George2 2009-08-05 14:34:49

回答

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

好,我糾正了我的代碼。 – George2 2009-08-05 14:39:55

+0

我已經發布了我對C#Dictionary和C#DataSet之間不一致行爲的進一步混淆,以檢查字符串唯一性,以及使行爲一致的任何解決方案嗎? – George2 2009-08-05 14:40:28

+0

謝謝ShuggyCoUk。我認爲對待他們同樣會產生更多感官。如何使用你的上面的System.Globalization.CultureInfo.CurrentCulture.CompareInfo.Compare函數檢查字符串的唯一性,即對於輸入字符串數組,我想輸出唯一性字符串忽略寬度。 – George2 2009-08-05 14:59:31

5

你在哪裏把字符串放入行中?它看起來像你正在創建空白行並插入其中2個?

這樣的事情?

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

我正在創建一個內存表,然後將批量插入到後端數據庫中。我已經發布了我對C#Dictionary和C#DataSet之間不一致行爲的進一步混淆,以檢查字符串唯一性,以及使行爲一致的任何解決方案? – George2 2009-08-05 14:36:07

+0

好,我糾正了我的代碼。 – George2 2009-08-05 14:39:18

1

它看起來像編碼是在第二串不同。調試時,第二個字符串回到垃圾。如果我刪除第二個字符串並在Visual Studio中輸入「2 c h」,它將正常工作。

+0

謝謝喬納森,但我無法刪除第二個字符串來制定解決方案。我需要處理這兩種形式。我已經發布了我對C#Dictionary和C#DataSet之間不一致行爲的進一步混淆,以檢查字符串唯一性,以及使行爲一致的任何解決方案? – George2 2009-08-05 14:42:01

6

這取決於你的意思是「相同」。

這兩個字符串有不同的Unicode值,但我懷疑在一些規範化規則下它們會是相同的。只需讓別人可以很容易地複製它沒有剪切和粘貼的問題,第二個字符串是:

"\uff12\uff43\uff48" 

這些都是「2CH」的"full width"版本。

編輯:爲了迴應你的編輯,明確了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)); 
    } 
} 

編輯:如果您設置DataTableCaseSensitive屬性爲true,我懷疑它會表現的與Dictionary相同。

+0

感謝Jon,我已經發布了關於C#Dictionary和C#DataSet之間不一致行爲的進一步混淆,以檢查字符串唯一性,以及使行爲一致的任何解決方案? – George2 2009-08-05 14:37:32

+0

如何使行爲一致?我在我的程序中同時使用Dictionary和DataSet,它們產生不同的結果......非常奇怪。無論它們是相同還是不同,我都想要有相同的行爲。任何解決方案 – George2 2009-08-05 14:41:24

+0

感謝Jon,將DataTable的CaseSensitive屬性設置爲true來解決我的問題。還有一個問題,我認爲這兩個字符串是字符串的全角或半角版本,它們不是區分大小寫的字符串 - 大寫和小寫,爲什麼控制大寫和小寫的CaseSensitive屬性很重要? – George2 2009-08-05 14:47:32