c # - '4' og '4' sammenstød i primærnøgle, men ikke i filsystem

Indlæg af Hanne Mølgaard Plasc

Problem



Der er DataTable med primærnøgle til at gemme information om filer. Der er der 2 filer, der adskiller sig i navne med symbolerne '4' og '4' (0xff14, et 'Fullwidth Digit Four' symbol). DataTable undlader at medtage dem begge på grund af mislykket unicitet. Men i Windows-filsystem ser de ud til at kunne eksistere sammen uden problemer.


Adfærd synes ikke at afhænge af lokalindstillinger, jeg har ændret 'Region &Sprog-> Formater-> Format' fra engelsk til japansk, også 'sprog for ikke-unicode-programmer' ændres. Locale blev trykt som 'jp-JP', 'en-GB'. Altid samme resultat.


spørgsmål:



  1. Hvad ville være mindre påtrængende måde at rette op på? Jeg kunne skifte til brug af containere i stedet for System.Data. * Men jeg kunne godt lide at undgå det. Er det muligt at definere tilpasset sammenligning for kolonnen eller på anden vis bedre kontrollere unikheden? forårsage andre problemer.

  2. Er der nogen chance for, at nogle globale indstillinger vil rette det uden at genopbygge softwaren?



Demo-programmet med fejl:


using System;
using System.Data;

namespace DataTableUniqueness
{
    class Program
    {
        static void Main(string[] args)
        {
            var changes = new DataTable("Rows");

            var column = new DataColumn { DataType = Type.GetType("System.String"), ColumnName = "File" };
            changes.Columns.Add(column);
            var primKey = new DataColumn[1];
            primKey[0] = column;
            changes.PrimaryKey = primKey;

            changes.Rows.Add("4.txt");
            try
            {
                changes.Rows.Add("4.txt"); // throws the exception
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e);
            }
        }
    }
}


Undtagelsen


Exception: System.Data.ConstraintException: Column 'File' is constrained to be unique.  Value '4.txt' is already present.
   at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action)
   at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent)
   at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean suppressEnsurePropertyChanged, Int32 position, Boolean fireEvent, Exception& deferredException)
   at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID, Int32 pos, Boolean fireEvent)
   at System.Data.DataRowCollection.Add(Object[] values)


PS: Lokaliteten ses som: Indtast billedbeskrivelse her [7]

Bedste reference


Ved at bruge DataType = typeof(object) du 'deaktivere' strengens normalisering. String lighed er stadig brugt til sammenligning. Jeg ved ikke, om der er andre bivirkninger.


Mere kompleks løsning: Gennemfør en 'wrapper' til klassen string:


public class MyString : IEquatable<MyString>, IComparable, IComparable<MyString>
{
    public static readonly StringComparer Comparer = StringComparer.InvariantCultureIgnoreCase;
    public readonly string Value;

    public MyString(string value)
    {
        Value = value;
    }

    public static implicit operator MyString(string value)
    {
        return new MyString(value);
    }

    public static implicit operator string(MyString value)
    {
        return value != null ? value.Value : null;
    }

    public override int GetHashCode()
    {
        return Comparer.GetHashCode(Value);
    }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is MyString))
        {
            return false;
        }

        return Comparer.Equals(Value, ((MyString)obj).Value);
    }

    public override string ToString()
    {
        return Value != null ? Value.ToString() : null;
    }

    public bool Equals(MyString other)
    {
        if (other == null)
        {
            return false;
        }

        return Comparer.Equals(Value, other.Value);
    }

    public int CompareTo(object obj)
    {
        if (obj == null)
        {
            return 1;
        }

        return CompareTo((MyString)obj);
    }

    public int CompareTo(MyString other)
    {
        if (other == null)
        {
            return 1;
        }

        return Comparer.Compare(Value, other.Value);
    }
}


Og så:


var changes = new DataTable("Rows");

var column = new DataColumn { DataType = typeof(MyString), ColumnName = "File" };
changes.Columns.Add(column);
var primKey = new DataColumn[1];
primKey[0] = column;
changes.PrimaryKey = primKey;

changes.Rows.Add((MyString)"a");
changes.Rows.Add((MyString)"4.txt");
try
{
    changes.Rows.Add((MyString)"4.txt"); // throws the exception
}
catch (Exception e)
{
    Console.WriteLine("Exception: {0}", e);
}

var row = changes.Rows.Find((MyString)"A");