在 .NET 中自动处理多语言属性 class
Automagically handling multi-lingual properties in a .NET class
我正在尝试在我的 ASP.NET Webforms(.NET 4.5,C#)应用程序中处理多种语言。
基本上,我的 SQL Server 2012 数据库中的某些实体具有 Name
或 Description
等属性,它们以三种语言存在 - 德语、法语、意大利语。
这些存储为列 Name_De
(德语)、Name_Fr
(法语)和 Name_It
(意大利语)。
当我从数据库创建我的 .NET 对象时,当然,我也在我的实体中获得了这三个属性 class。但是为了在屏幕上显示,例如在网格中,如果我能以某种方式 "magically" 始终显示 "right" 语言就好了。这应该基于 Thread.Current.CurrentUICulture.TwoLetterISOLanguageName
(其中 returns de
、fr
或 it
,具体取决于浏览器的语言偏好)。
所以我希望能够以某种方式创建例如一个 .NET 属性,允许我做这样的事情:
基础 "Module" 实体 - 从现有 SQL 服务器数据库生成:
public partial class Module
{
public string ModuleCode { get; set; }
public string Name_De { get; set; }
public string Name_Fr { get; set; }
public string Name_It { get; set; }
... // other properties
}
单独文件中的部分扩展名
public partial class Module
{
[Multilingual]
public string Name { get; set; }
}
基本思路是:我可以访问 Module.Name
属性,并且根据 CurrentUICulture
的当前设置,Name_De
、[=当我访问 Name
属性.
的 getter 时,将获取 16=] 或 Name_It
在 C# 中可以完成这样的事情吗?我看过很多自定义属性的实现,但似乎从来没有做过这样的事情...
假设您使用两个独立的实体(一个由您的 SQL 实体生成,另一个 "business entity" 仅包含 Name
属性),您是否愿意使用像 AutoMapper ?
这样的东西
如果是,那么您可以调整解析函数以根据当前线程文化映射实体。
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
return dto.Name_De;
case "FR":
return dto.Name_Fr;
// ...
default :
return String.Empty;
}
这将适用于您的方案。
如果这是一个适合您的解决方案,我认为这个问题非常接近您正在寻找的问题:Automapper Mapping for Localization Resolver in a Multi-Language Website
如果你真的走自定义属性路线,恐怕你将不得不处理反射和字符串解析。据我所知,没有内置的方法可以使用 .NET 提供的本地化功能来执行此操作。 AutoMapper 会向您隐藏它。
在这种情况下自定义属性的问题在于您仍在尝试访问 Name
属性。您正试图通过使其访问其他属性来 "shadow" 属性 的默认行为。如果我理解正确,你希望 Multilingual
自定义属性将你的 属性 变成:
public String Name
{
get
{ switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
return dto.Name_De;
case "FR":
return dto.Name_Fr;
// ...
default :
return String.Empty;
}
}
}
如果这是正确的,那么您将无法使用属性轻松做到这一点,因为属性永远不会意识到 Name_De
属性.[=18 的存在=]
其他仍然不是您想要的选项:
void Main()
{
Module mod = new Module();
mod.Name_De = "name";
mod.Name_Fr = "nom";
// This is the unfortunate nasty bit. I address the property using its name
// in a String which is just bad. I don't think there is a way
// you will be able to address the ".Name" property directly and have
// it return the localized value through your custom attribute though
String localizedValue = mod.GetLocalizedProperty("Name");
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class MultilingualAttribute : Attribute
{
public MultilingualAttribute()
{
}
}
public static class ModuleExtensions
{
public static String GetLocalizedProperty(this Module module, String propName)
{
var type = typeof(Module);
var propInfo = type.GetProperty(propName);
// Make sure the prop really is "Multilingual"
if(Attribute.IsDefined(propInfo, typeof(MultilingualAttribute)))
{
String localizedPropName = propInfo.Name;
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
localizedPropName += "_De";
return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
case "FR":
localizedPropName += "_Fr";
return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
}
}
return String.Empty;
}
}
public class Module
{
public String Name_De {get; set;}
public String Name_Fr {get; set;}
[Multilingual]
public String Name {get; set;}
public Module()
{
}
}
不幸的是,我不知道有更强大的方法来使用自定义属性来满足您的需求。坦率地说,我认为这不是一个好的解决方案,发布它只是因为我想看看我可以用自定义属性做什么。在 more "normal" 属性 上使用此代码没有实际意义,后者会以更清晰的方式(无属性)做同样的事情。正如您在原始问题中所说,您的目标是拦截对 Name 属性 的调用,但这并没有实现。
我正在尝试在我的 ASP.NET Webforms(.NET 4.5,C#)应用程序中处理多种语言。
基本上,我的 SQL Server 2012 数据库中的某些实体具有 Name
或 Description
等属性,它们以三种语言存在 - 德语、法语、意大利语。
这些存储为列 Name_De
(德语)、Name_Fr
(法语)和 Name_It
(意大利语)。
当我从数据库创建我的 .NET 对象时,当然,我也在我的实体中获得了这三个属性 class。但是为了在屏幕上显示,例如在网格中,如果我能以某种方式 "magically" 始终显示 "right" 语言就好了。这应该基于 Thread.Current.CurrentUICulture.TwoLetterISOLanguageName
(其中 returns de
、fr
或 it
,具体取决于浏览器的语言偏好)。
所以我希望能够以某种方式创建例如一个 .NET 属性,允许我做这样的事情:
基础 "Module" 实体 - 从现有 SQL 服务器数据库生成:
public partial class Module
{
public string ModuleCode { get; set; }
public string Name_De { get; set; }
public string Name_Fr { get; set; }
public string Name_It { get; set; }
... // other properties
}
单独文件中的部分扩展名
public partial class Module
{
[Multilingual]
public string Name { get; set; }
}
基本思路是:我可以访问 Module.Name
属性,并且根据 CurrentUICulture
的当前设置,Name_De
、[=当我访问 Name
属性.
Name_It
在 C# 中可以完成这样的事情吗?我看过很多自定义属性的实现,但似乎从来没有做过这样的事情...
假设您使用两个独立的实体(一个由您的 SQL 实体生成,另一个 "business entity" 仅包含 Name
属性),您是否愿意使用像 AutoMapper ?
如果是,那么您可以调整解析函数以根据当前线程文化映射实体。
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
return dto.Name_De;
case "FR":
return dto.Name_Fr;
// ...
default :
return String.Empty;
}
这将适用于您的方案。
如果这是一个适合您的解决方案,我认为这个问题非常接近您正在寻找的问题:Automapper Mapping for Localization Resolver in a Multi-Language Website
如果你真的走自定义属性路线,恐怕你将不得不处理反射和字符串解析。据我所知,没有内置的方法可以使用 .NET 提供的本地化功能来执行此操作。 AutoMapper 会向您隐藏它。
在这种情况下自定义属性的问题在于您仍在尝试访问 Name
属性。您正试图通过使其访问其他属性来 "shadow" 属性 的默认行为。如果我理解正确,你希望 Multilingual
自定义属性将你的 属性 变成:
public String Name
{
get
{ switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
return dto.Name_De;
case "FR":
return dto.Name_Fr;
// ...
default :
return String.Empty;
}
}
}
如果这是正确的,那么您将无法使用属性轻松做到这一点,因为属性永远不会意识到 Name_De
属性.[=18 的存在=]
其他仍然不是您想要的选项:
void Main()
{
Module mod = new Module();
mod.Name_De = "name";
mod.Name_Fr = "nom";
// This is the unfortunate nasty bit. I address the property using its name
// in a String which is just bad. I don't think there is a way
// you will be able to address the ".Name" property directly and have
// it return the localized value through your custom attribute though
String localizedValue = mod.GetLocalizedProperty("Name");
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class MultilingualAttribute : Attribute
{
public MultilingualAttribute()
{
}
}
public static class ModuleExtensions
{
public static String GetLocalizedProperty(this Module module, String propName)
{
var type = typeof(Module);
var propInfo = type.GetProperty(propName);
// Make sure the prop really is "Multilingual"
if(Attribute.IsDefined(propInfo, typeof(MultilingualAttribute)))
{
String localizedPropName = propInfo.Name;
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "DE":
localizedPropName += "_De";
return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
case "FR":
localizedPropName += "_Fr";
return type.GetProperty(localizedPropName).GetValue(module, null).ToString();
}
}
return String.Empty;
}
}
public class Module
{
public String Name_De {get; set;}
public String Name_Fr {get; set;}
[Multilingual]
public String Name {get; set;}
public Module()
{
}
}
不幸的是,我不知道有更强大的方法来使用自定义属性来满足您的需求。坦率地说,我认为这不是一个好的解决方案,发布它只是因为我想看看我可以用自定义属性做什么。在 more "normal" 属性 上使用此代码没有实际意义,后者会以更清晰的方式(无属性)做同样的事情。正如您在原始问题中所说,您的目标是拦截对 Name 属性 的调用,但这并没有实现。