通过在运行时在泛型方法中进行类型转换来使用递归函数

Posted

技术标签:

【中文标题】通过在运行时在泛型方法中进行类型转换来使用递归函数【英文标题】:Using the recursive function by making the type transformation in the generic method at run time 【发布时间】:2021-09-06 00:27:04 【问题描述】:

我有一个来自 AppLayerGroup 类的列表,在这个列表中我有另一个来自 AppLayer 类的列表。我想要做的是将发送到 TranslateList 方法的列表的每个属性翻译成我选择的语言。如果列表的每个属性的对应值存在于视图中,我更新它。如果属性是一个列表,我会尝试在递归函数的帮助下将新列表发送回 Translate 方法。但是类型'T'与第一次类型不同,我需要在运行时转换它但我不知道该怎么做。

    public class AppLayer : IEntity
    
        public int Id  get; set; 
        public int AppLayerGroupId  get; set; 
        public string LayerName  get; set; 
    

    public class AppLayerGroup : IEntity
    
        public int Id  get; set; 
        public string GroupKey  get; set; 
        public virtual ICollection<AppLayer> AppLayer  get; set; 
    
    public static IEnumerable<T> TranslateList<T>(this IEnumerable<T> data)
    
        var _httpContextAccessor = (IHttpContextAccessor)ServiceTool.ServiceProvider.GetService(typeof(IHttpContextAccessor));
        var userId = _httpContextAccessor.HttpContext?.User.Claims.FirstOrDefault(x => x.Type.EndsWith("nameidentifier"))?.Value;
        var _cacheManager = (ICacheManager)ServiceTool.ServiceProvider.GetService(typeof(ICacheManager));

        short appLangId = Convert.ToInt16(_cacheManager.Get($"CacheKeys.UserLang=userId"));

        Translate(data, appLangId);

        return data;
    

    

    public static IEnumerable<T> Translate<T>(IEnumerable<T> data, short appLangId)
    
        string classname = (data.FirstOrDefault() as Castle.DynamicProxy.IProxyTargetAccessor).DynProxyGetTarget().GetType().BaseType.Name;

        var _vAppLookupLanguageRepository = (IVAppLookupLanguageRepository)ServiceTool.ServiceProvider.GetService(typeof(IVAppLookupLanguageRepository));
        var langList = _vAppLookupLanguageRepository.GetList(a => a.EntityName == classname && a.AppLanguageId == appLangId);

        if (langList.IsAny() && data.IsAny())
        
            foreach (var item in data )
            
                foreach (PropertyInfo prop in item.GetType().GetProperties())
                
                    if (prop.PropertyType.GetInterface("IEnumerable").Name == "IEnumerable")
                    
                        var subList = (IEnumerable)prop.GetValue(item, null);

                        Translate((IEnumerable<T>)subList, 2); //I should submit the type of subList instead of 'T'
                    
                    if (langList.Any(a => a.ColumnName == prop.Name))
                        prop.SetValue(item, langList.FirstOrDefault(a => a.UniqueValue == prop.GetValue(item).ToString()).LanguageValue, null);
                
            
        

        return data;
    

当我查询 AppLayerGroup 时,AppLayerGroup 列表将通过本地化每个列表元素内的属性返回。我希望它执行相同的操作并将其本地化到 AppLayerGroup 列表下的 AppLayer 列表中。

我做了一些研究,但找不到正确的结果。

【问题讨论】:

@Sinatr 我正在尝试翻译每个列表属性。我正在使用 T 能够发送到递归函数。你有更好的建议吗? 我的错,我以某种方式将其理解为本地化。忽略我的评论。 这看起来您的应用程序需要全球化和本地化。对吗? @DanielDearlove 实际上试图准确地进行本地化。 @omerfarukaktas 如果您正在本地化,您是否已经遵循Globalization and Localization 的建议?另外,我仍在尝试弄清楚为什么您必须使用反射而不是为您的特定类创建 Translate() 方法? 【参考方案1】:

如果您尝试翻译少数类中的字段,例如您的示例中的 AppLayerAppLayerGroup,则直接实现翻译并避免反射可能是更好的选择:

/// <summary>
/// Translates the string fields from the base language to a target language
/// </summary>
public static AppLayer Translate(AppLayer input, short appLangId)

    string classname = input.GetType().Name;
    var _vAppLookupLanguageRepository = (IVAppLookupLanguageRepository)ServiceTool.ServiceProvider.GetService(typeof(IVAppLookupLanguageRepository));
    var langList = _vAppLookupLanguageRepository.GetList(
        a => a.EntityName == classname && 
             a.AppLanguageId == appLangId &&
             a.ColumnName == "LayerName");

    string newLayerName = langList.FirstOrDefault(a => a.UniqueValue == input.LayerName).LanguageValue, null);

    return new AppLayer
    
        Id = input.Id,
        AppLayerGroupId = input.AppLayerGroupId,
        LayerName = newLayerName
    ;

我刚刚在键盘上敲了这个,所以它不会完全正确。如果您重构为一个通用的private static 翻译查找函数,在该函数中将语言存储库作为参数传递,那么您可以像处理AppLayer 一样处理AppLayerGroup 属性。您可以遍历 AppLayerGroup.AppLayer 集合。

【讨论】:

AppLayerGroup 只是一个小例子,项目中有很多这样的类我需要本地化,为它们编写不同的方法对我来说没有多大意义,并且这需要很多时间。 这正是我所期望的。在已部署的应用程序中,我怀疑您是否可以应用 Source Generators 以便留下反射。我建议您至少设置一些需要转换的最复杂数据类型的测试用例。此外,可能值得添加一个类属性来标识可以翻译的类型,并且为不应该翻译的类型抛出异常。

以上是关于通过在运行时在泛型方法中进行类型转换来使用递归函数的主要内容,如果未能解决你的问题,请参考以下文章

在泛型方法中处理类型创建

泛型方法与桥方法

涉及泛型对象的泛型属性的赋值无法在泛型函数中正确进行类型检查

无法在泛型方法中将类型更改为可为空

在泛型方法中返回原始集合类型

如何在泛型类型中使用 linq 包含函数