Не ASCII символы в идентификаторах C # Ссылка NHibernate - PullRequest
5 голосов
/ 23 марта 2011

Я попытался ввести не идентификаторы ASCII в идентификаторах C #, и программа компилируется и работает очень хорошо (по крайней мере, на первый взгляд).Чтобы быть более точным, я использую хорватские диакритические знаки (čćđšž) в перечислениях.Мне действительно нужно использовать эти специальные символы, потому что я отображаю строковые перечисления как объекты значений в NHibernate.Было бы очень некрасиво избегать этих стандартных символов при отображении их в качестве поисков пользователя.Прежде чем я начну использовать перечисления таким образом в большом масштабе, мне действительно нужно знать, есть ли какие-либо последствия (скрытые ловушки) для такой техники программирования (особенно в отношении NHibernate)?Или, если у вас есть лучший способ справиться с этим, пожалуйста, сообщите мне.

Кроме того, есть ли проблемы с инструментами, используемыми для рефакторинга, SVN и т. Д.

Ответы [ 4 ]

6 голосов
/ 23 марта 2011

Язык C # использует кодировку Unicode, что означает, что ваш специальный символ не будет проблемой. Тем не менее, мне нравится хранить мой код на английском без специальных символов. Мне еще предстоит найти проблему, которая оправдывает использование имен, специфичных для культуры.

Из спецификации языка C #:

Программа на C # состоит из одного или нескольких исходные файлы, формально известные как единицы компиляции (§9.1). Источник файл представляет собой упорядоченную последовательность Unicode персонажи. Исходные файлы обычно иметь личную переписку с файлы в файловой системе, но это переписка не требуется. За максимальная переносимость, рекомендуется что файлы в файловой системе должны быть закодированы с кодировкой UTF-8.

Раздел 2.1 ( Спецификация языка Microsoft C # )

3 голосов
/ 23 марта 2011

Я сделал этот пользовательский тип пользователя для безопасного преобразования из enum в int для NHibernate. Вы должны изменить функцию, чтобы использовать строку вместо int. Затем вы можете изменить метод «NullSafeGet», чтобы выполнить преобразование из значения базы данных в значение enum. Сделав это, вы можете использовать обычные символы для значений перечисления и читаемых пользователем имен в вашей базе данных. РЕДАКТИРОВАТЬ: я сделал изменения сам. Вы можете использовать этот класс для своего пользовательского типа. Вам следует реализовать метод «SpecialConversion» для преобразования из вашей специальной строки в enum и наоборот.

public class EnumToSpecialStringType<TEnum> : IUserType
{
    #region IUserType Members

    /// <summary>
    /// Reconstruct an object from the cacheable representation. At the very least this
    /// method should perform a deep copy if the type is mutable. (optional operation)
    /// </summary>
    /// <param name="cached">the object to be cached</param>
    /// <param name="owner">the owner of the cached object</param>
    /// <returns>a reconstructed object from the cachable representation</returns>
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    /// <summary>
    /// Return a deep copy of the persistent state, stopping at entities and at collections.
    /// </summary>
    /// <param name="value">generally a collection element or entity field</param>
    /// <returns>a copy</returns>
    public object DeepCopy(object value)
    {
        return value;
    }

    /// <summary>
    /// Transform the object into its cacheable representation. At the very least this
    /// method should perform a deep copy if the type is mutable. That may not be enough
    /// for some implementations, however; for example, associations must be cached as
    /// identifier values. (optional operation)
    /// </summary>
    /// <param name="value">the object to be cached</param>
    /// <returns>a cacheable representation of the object</returns>
    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    /// <summary>
    /// Compare two instances of the class mapped by this type for persistent "equality"
    /// ie. equality of persistent state
    /// </summary>
    /// <param name="x"/>
    /// <param name="y"/>
    /// <returns/>
    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.Equals(y);
    }

    /// <summary>
    /// Get a hashcode for the instance, consistent with persistence "equality"
    /// </summary>
    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    /// <summary>
    /// Are objects of this type mutable?
    /// </summary>
    public bool IsMutable
    {
        get { return false; }
    }

    /// <summary>
    /// Retrieve an instance of the mapped class from a ADO.NET resultset.
    /// Implementors should handle possibility of null values.
    /// </summary>
    /// <param name="rs">a IDataReader</param>
    /// <param name="names">column names</param>
    /// <param name="owner">the containing entity</param>
    /// <returns/>
    /// <exception cref="HibernateException">HibernateException</exception>
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var value = NHibernateUtil.String.NullSafeGet(rs, names[0]) as string;

        // Put you special conversion here (string -> enum)
        var converted = SpecialConversion(value);

        return converted;
    }

    /// <summary>
    /// Write an instance of the mapped class to a prepared statement.
    /// Implementors should handle possibility of null values.
    /// A multi-column type should be written to parameters starting from index.
    /// </summary>
    /// <param name="cmd">a IDbCommand</param>
    /// <param name="value">the object to write</param>
    /// <param name="index">command parameter index</param>
    /// <exception cref="HibernateException">HibernateException</exception>
    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var parameter = (IDataParameter)cmd.Parameters[index];

        // Do conversion from your enum to database string value
        var converted = SpecialConversion(value);

        parameter.Value = converted;
    }

    /// <summary>
    /// During merge, replace the existing (<paramref name="target"/>) value in the entity
    /// we are merging to with a new (<paramref name="original"/>) value from the detached
    /// entity we are merging. For immutable objects, or null values, it is safe to simply
    /// return the first parameter. For mutable objects, it is safe to return a copy of the
    /// first parameter. For objects with component values, it might make sense to
    /// recursively replace component values.
    /// </summary>
    /// <param name="original">the value from the detached entity being merged</param>
    /// <param name="target">the value in the managed entity</param>
    /// <param name="owner">the managed entity</param>
    /// <returns>the value to be merged</returns>
    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    /// <summary>
    /// The type returned by <c>NullSafeGet()</c>
    /// </summary>
    public Type ReturnedType
    {
        get
        {
            return typeof(TEnum);
        }
    }

    /// <summary>
    /// The SQL types for the columns mapped by this type. 
    /// </summary>
    public SqlType[] SqlTypes
    {
        get
        {
            return new[] { new SqlType(DbType.String) };
        }
    }

    #endregion
}

Я использую беглый NHibernate, и мой способ сопоставления моей колонки с этим пользовательским типом был:

Map(x => x.PropertyName, "ColumnName").CustomType<EnumToSpecialStringType<EnumType>>();

РЕДАКТИРОВАТЬ: Вот пост о том, как сопоставить тип пользователя с помощью файла сопоставления XML:

Отображение nHibernate на пользовательские типы

1 голос
/ 24 марта 2011

Да, я считаю, что подводный камень.

Отображение поисков для пользователя и ведение списка возможных (уникальных) элементов в базе данных лучше хранить отдельно.Особенно, если ваше приложение будет поддерживать другие языки в будущем.

Не очень объектно-ориентированный, в вашем коде может быть класс, который представляет собой прямое отображение между вашим перечислением и значением соответствующего языка, как в отображении nhibernate, например:

<class name="DropDown" table="DropDown_Language">
    <!-- map onto the ENUMeration -->
    <id name="UniqueID" column="Id" type="Int32" >
        <generator class="identity" />
    </id>
    <property name="DropDownType" column="DropDownTypeId" type="DropDownType, Domain"/>
    <property name="Language" column="LanguageId" type="LanguageReferenceType,  "/>
    <property name="DropDownTypeDescription" column="DropDownTypeDescription" type="string"/>
</class>

В столбце DropDownTypeDescription вы должны указать значения раскрывающегося списка.

Надеюсь, я понял ваш вопрос: -)

1 голос
/ 23 марта 2011

Я просто пишу здесь примеры, чтобы показать, как вы можете сделать отображение.

Рассмотрите ваше перечисление, где все значения содержат символы не-ASCII:

public enum MyEnum
{
    NonAsciiName1,
    NonAsciiName2,
    NonAsciiName3,
}

Вы можете изменить егочтобы сделать это, когда все значения имеют символы ASCII:

public enum MyEnum
{
    AsciiName1,
    AsciiName2,
    AsciiName3,
}

public static class MyEnumExtensions
{
    static readonly Dictionary<MyEnum, string> map = new Dictionary<MyEnum, string>
    {
        { MyEnum.AsciiName1, "NonAsciiName1" },
        { MyEnum.AsciiName2, "NonAsciiName2" },
        { MyEnum.AsciiName3, "NonAsciiName3" },
    };

    public static string GetValue(this MyEnum key)
    {
        return map[key];
    }
}

Тогда вашему коду потребуются небольшие изменения, чтобы использовать это:

// you probably had something like:
var myEnumValue = MyEnum.NonAsciiName1;
var value = myEnumValue.ToString();

// now becomes:
var myEnumValue = MyEnum.AsciiName1;
var value = myEnumValue.GetValue();

Или если DEHAAS предложил, используйте атрибутыработает аналогичным образом.Но тогда вам придется использовать отражение, чтобы получить значения, которые немного снижают производительность.

using System.ComponentModel;

public enum MyEnum
{
    [DescriptionAttribute("NonAsciiName1")] AsciiName1,
    [DescriptionAttribute("NonAsciiName2")] AsciiName2,
    [DescriptionAttribute("NonAsciiName3")] AsciiName3,
}

public static class MyEnumExtensions
{
    public static string GetValue(this MyEnum key)
    {
        return typeof(MyEnum).GetField(key.ToString())
                             .GetCustomAttributes(typeof(DescriptionAttribute), false)
                             .Cast<DescriptionAttribute>()
                             .Single()
                             .Description;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...