繁体   English   中英

在.NET类中自动处理多语言属性

[英]Automagically handling multi-lingual properties in a .NET class

我正在尝试在我的ASP.NET Webforms(.NET 4.5,C#)应用程序中处理多种语言。

基本上,我在SQL Server 2012数据库中的某些实体具有诸如NameDescription类的属性,它们以三种语言(德语,法语,意大利语)存在。

这些存储为Name_De (德语), Name_Fr (法语)和Name_It (意大利语)列。

当然,当我从数据库创建.NET对象时,我也在实体类中获得了这三个属性。 但是对于在屏幕上显示,例如在网格中,如果我能以某种方式“神奇地”总是显示“正确的”语言,那将是很好的。 这应该基于Thread.Current.CurrentUICulture.TwoLetterISOLanguageName (根据浏览器的语言首选项返回defrit )。

所以我希望能够以某种方式创建一个.NET属性,该属性使我可以执行以下操作:

基本的“模块”实体-从现有的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_DeName_FrName_It的值。

可以在C#中完成类似的事情吗? 我看过很多自定义属性的实现,但是似乎从来没有做过这样的事情...

假设您使用两个单独的实体(一个由您的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映射

如果您确实遵循自定义属性路线,恐怕您将不得不处理反射问题和字符串解析。 AFAIK,.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属性的存在。

仍然不是您想要的其他选择:

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属性的调用,但这没有实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM