C# I';我目前正在使用反射来实现这一点,有更好的方法吗?

C# I';我目前正在使用反射来实现这一点,有更好的方法吗?,c#,vb.net,reflection,C#,Vb.net,Reflection,o将始终来自EntityRef/TEntity(来自linq 2 sql) 我可以使用c#或vb.net解决方案(如果不能,我会将其转换为vb.net) 小背景 我有一个这样的数据库 tableUser ----------------- id name countryid tableCountry -------- countryid descEn descFr 当我显示有关用户的信息时,我想轻松地显示在应用程序中选择的良好语言 举个例子,我有更多的表和更多的查找表 使用linq 2 sq

o将始终来自EntityRef/TEntity(来自linq 2 sql)

我可以使用c#或vb.net解决方案(如果不能,我会将其转换为vb.net)

小背景

我有一个这样的数据库

tableUser
-----------------
id
name
countryid

tableCountry
--------
countryid
descEn
descFr
当我显示有关用户的信息时,我想轻松地显示在应用程序中选择的良好语言

举个例子,我有更多的表和更多的查找表


使用linq 2 sql如果数据库中的字段为null,则对象将为“nothing”(
null
),我将使用第一个捕获它,如果,则我将得到相应的语言字段,除非您可以通过某种实体基类或代码生成和分部类将
desc
方法集成到每个对象中,否则将需要运行时反射

代码生成方法:对于每个实体类,如果它包含一个或多个
descFoo
属性,则生成一个
desc
属性以提取正确的属性。如果无法在编写CodeDom之前对其进行修改,还可以编译实体类、反映/内省结果、生成分部类,并使用添加的代码重新编译

但是,由于这些是实体类,所以在我看来,模式更改可能更可取。不要使用多个
descFoo
列,而是添加一个由{entity PK,language,text}组成的表。

使用当前的设计,您无法做得更好。相反,您应该考虑进行重大的重新设计,并从专用表中获取本地化值,而不是为所有语言提供列

您的描述字段可以只保存一个
DescriptionId
,您可以通过另外提供一个语言标识符在
Descriptions
表中查找该id

DescriptionId | Language | Description
--------------------------------------
            1 | fr       | French Foo
            1 | en       | English Foo
            2 | fr       | French Bar
            2 | fr       | English Bar
这很容易允许以后添加其他语言。如果您不希望使用其他语言,可以使用以下语言

DescriptionId | English     | French
----------------------------------------
            1 | English Foo | French Foo
            2 | English Bar | French Bar
public static GetLocalizedDescription(this ILocalizedEntity entity)
{
    if (entity == null)
    {
        return String.Empty;
    }
    else
    {
        switch (Session.Language)
        {
            case Language.English:
                return entity.descrEn;
                break;

            case Language.French:
                return entity.descrFr;
                break;

            default:
                throw new InvalidOperationException();
        }
    }
}
只是澄清一下——我不建议为每个实体或列引入一个本地化表,而是为所有实体和列引入一个本地化表。因此,包含可本地化信息的所有列都将成为同一表的外键。因此,可以集中代码来获取本地化字符串,而不是为每个实体重新创建它

我的想法与papper1337相同,但没有提出,因为我相信重新设计数据库是一条路要走。我会提出以下建议

DescriptionId | English     | French
----------------------------------------
            1 | English Foo | French Foo
            2 | English Bar | French Bar
public static GetLocalizedDescription(this ILocalizedEntity entity)
{
    if (entity == null)
    {
        return String.Empty;
    }
    else
    {
        switch (Session.Language)
        {
            case Language.English:
                return entity.descrEn;
                break;

            case Language.French:
                return entity.descrFr;
                break;

            default:
                throw new InvalidOperationException();
        }
    }
}
创建一个接口
ILocalizedEntity

public interface ILocalizedEntity
{
    String descEn { get; }
    String descFr { get; }
}
将此接口添加到所有本地化实体。这很容易做到,因为LINQtoSQL创建了分部类。例如,在C#中,我将创建一个新文件
Country.cs
,并添加以下代码

public partial class Country : ILocalizedEntity
{
}
该接口由LINQ到SQL生成的代码实现

现在创建一个如下所示的方法

DescriptionId | English     | French
----------------------------------------
            1 | English Foo | French Foo
            2 | English Bar | French Bar
public static GetLocalizedDescription(this ILocalizedEntity entity)
{
    if (entity == null)
    {
        return String.Empty;
    }
    else
    {
        switch (Session.Language)
        {
            case Language.English:
                return entity.descrEn;
                break;

            case Language.French:
                return entity.descrFr;
                break;

            default:
                throw new InvalidOperationException();
        }
    }
}
这是一种C#扩展方法,您可以按如下方式使用它

someEntity.GetLocalizedDescription();

我同意丹尼尔·布鲁克纳的观点

也就是说,另一种实现方式是使用如下接口:

public interface IEnglish
{
 public string DescriptionEN { get; }
}

public interface IFrench
{
 public string DescriptionFR { get; }
}

public interface IMultilingual : IEnglish, IFrench { }

public void desc<T>(ref T o, string propPrefix) where T : IMultilingual
{
 return Sess.lang = Sess.elang.en ? o.DescriptionEN : o.DescriptionFR
}
公共界面IEnglish
{
公共字符串描述符{get;}
}
公共接口IFrench
{
公共字符串描述符fr{get;}
}
多语言公共界面:IEnglish,IFrench{}
public void desc(ref T o,string propPrefix),其中T:i多语言
{
返回Sess.lang=Sess.elang.en?o.DescriptionEN:o.DescriptionFR
}

然后,任何包含英语/法语属性的类都将实现iMultilangual并从此过上幸福的生活。

您使用该代码的具体目的是什么?根据配置的语言,他似乎在调用带有“en”或“fr”前缀的方法。它将返回法语(descfr字段)和英语之间的正确文本(descen field)回答这个问题似乎需要更多的上下文。你最初用反思来解决这个问题有什么特别的原因吗?我倾向于认为国际化依赖于一次加载资源,然后以同样的方式引用这些资源(所有内容都只需要Desc;事实上,Desc中当前有一个英语或法语(或德语等)字符串不属于请求该字符串的对象的责任范围)这就是我现在看到的问题。这个问题在应用程序内部,选择哪个字段模式修订是更好的方法。但是,如果您使用双语言1表方法,那么为什么不使用“if(var.Sess.lang=Sess.elang.en)然后Return tableCountry.descen Else Return tableCountry.descfr End if”。如果那里的代码很差,我深表歉意,因为我进入VB已有很长时间了。@Lazarus,我的模式为每个字段都提供了专用的表格,可以是法语或英语,所以我对这部分已经很在行了,请阅读我问题的结尾,了解实际问题,如果代码中的每一个地方都有上百个时间不是一个好的选择,请不要忘记,我会这样做需要检查对象是否为null,如果不是,那么我可以决定要使用哪个字段。您现在没有这个功能-您将本地化绑定到不同的表,而不是所有本地化的单个表。因此,您无法集中代码选择所需的语言,但您可以使用单个表。这可能会导致另一个问题是,你需要多出一列来确定行的含义,它是一个单位、一个国家、一种物质、一种类型等吗?从那时起,你需要在代码中添加一个枚举和一个与之链接的表来识别这类信息。回到代码,你需要在每个下拉列表中添加更多代码等,以确保你列出了co请更正全局表中的信息。我不确定是否要这样做……除非您知道一种简单的方法来解决我刚才所说的问题。该类来自linq2sql对象,因此我无法修改它。您可以通过