我试图在C#标识符中输入非ASCII字符,程序编译并运行得很好(至少乍一看)。更确切地说,我在枚举中使用克罗地亚变音字符(čćđšž)。我真的需要使用这些特殊字符,因为我将字符串枚举映射为NHibernate中的值对象。在将它们显示为对用户的查找时,必须避免使用这些标准字符真的很难看。在我以这种方式大规模开始使用枚举之前,我真的需要知道这种编程技术是否存在任何影响(隐藏的陷阱)(特别是关于NHibernate)?或者,如果您有更好的处理方式,请告诉我。
此外,用于重构的工具,SVN等是否存在任何问题。
答案 0 :(得分:6)
C#语言使用unicode编码,这意味着您的特殊字符不会出现问题。但是,我喜欢在没有特殊字符的情况下保留我的英文代码。我还没有找到一个合理使用特定文化命名的问题。
来自C#语言规范:
C#程序由一个或多个组成 源文件,正式称为 编制单位(§9.1)。来源 file是Unicode的有序序列 字符。通常是源文件 与...一一对应 文件系统中的文件,但是这个 不需要通信。对于 最大可移植性,建议使用 编码文件系统中的文件 使用UTF-8编码。
答案 1 :(得分:3)
我将这个自定义用户类型安全地从enum转换为int for NHibernate。你应该将函数更改为使用string而不是int。然后,您可以更改方法“NullSafeGet”以进行从数据库值到枚举值的转换。这样,您可以在数据库中使用普通字符作为枚举值和用户可读名称。
编辑:我自己做了改动。您可以将此类用于自定义用户类型。你应该实现“SpecialConversion”方法,从你的特殊字符串转换为枚举,反之亦然。
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和我的方式使用这个自定义usertype映射我的列:
Map(x => x.PropertyName, "ColumnName").CustomType<EnumToSpecialStringType<EnumType>>();
编辑:这是一篇关于如何使用xml映射文件映射用户类型的帖子:
答案 2 :(得分:1)
我只是在这里编写示例来说明如何进行映射。
考虑所有值包含非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;
}
}
答案 3 :(得分:1)
是的,我认为这是一个陷阱。
向用户显示查找并保留数据库中可能(唯一)项目的列表可以更好地单独保存。特别是如果您的应用程序将来支持其他语言。
不是非常面向对象你可以在你的代码中有一个类,它是你的枚举和相应语言的值之间的直接映射,就像这样的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列中输入下拉列表的值。
希望我理解你的问题: - )