我正在尝试在我的ASP.NET Webforms (.NET 4.5,C#)应用程序中处理多种语言。
基本上,我在SQL Server2012数据库中的一些实体具有像Name或Description这样的属性,它们以三种语言存在--德语、法语和意大利语。
这些列存储为Name_De (德语)、Name_Fr (法语)和Name_It (意大利语)列。
当然,当我从数据库创建.NET对象时,我也会在实体类中获得这三个属性。但为了在屏幕上显示,例如在网格中,如果我能以某种方式“神奇地”始终显示“正确”的语言,那就太好了。这应该基于Thread.Current.CurrentUICulture.TwoLetterISOLanguageName (它返回de、fr或it,具体取决于浏览器的语言首选项)。
因此,我希望能够以某种方式创建一个.NET属性,它允许我执行以下操作:
基本"Module“实体-从现有SQL Server数据库生成:
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属性的getter时,将获取Name_De、Name_Fr或Name_It的值。
在C#中可以做这样的事情吗?我看过很多自定义属性实现,但似乎从来没有做过这样的事情……
发布于 2016-08-06 00:25:54
假设您使用两个独立的实体(一个由您的SQL实体生成,另一个“业务实体”只包含Name属性),您是否愿意使用AutoMapper之类的东西?
如果是,那么您可以调整resolve函数,以根据当前线程区域性映射实体。
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属性。您试图通过使该属性访问其他属性来“隐藏”该属性的默认行为。如果我理解正确的话,您希望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属性的存在。
发布于 2016-08-06 02:30:39
另一种选择仍然不是你想要的:
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()
{
}
}不幸的是,我不知道还有比这更强大的方法来使用自定义属性来满足您的需求。坦率地说,我不认为这是一个好的解决方案,只是因为我想看看我能用自定义属性做些什么。在一个更“正常”的属性上使用这段代码并没有什么实际意义,因为它会以一种更清晰的方式(没有属性)做同样的事情。正如您在原始问题中所说的,您的目标是拦截对Name属性的调用,但这并不能实现它。
https://stackoverflow.com/questions/38793162
复制相似问题