C#使用OfType根据类型获取集合

首先我们来看MSDN对OfType的定义

 

根据描述可知,OfType在Linq的命名空间下,是IEnumerable的扩展方法,泛型的输入和输出是一样的,所以这个方法可以是协变的,但是微软并没有这么做,原因应该是协变是在.net framework 4.0之后才实现的,而OfType早于4.0,微软并没有特意再做修改了。

该方法可以将IEnumerable集合做类型区分。

我们来看基本用法

        public class Animal
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
        public class Cat : Animal { }
        public class Dog : Animal { }

       static void Main(string[] args)
        {
            List<Animal> animals = new List<Animal>
            {
                new Cat(){  Name="Tom", Age=3},
                new Cat(){  Name="Jeck", Age=3},
                new Dog(){  Name="Bob", Age=3},
                new Dog(){  Name="John", Age=3}
            };

          var cats = animals.OfType<Cat>().ToList();  //output Tom,Bob
          var dogs = animals.OfType<Dog>().ToList();  //output Bob,John
          var animalsOut = animals.OfType<Animal>().ToList();  //output all
        }

我们可以看到,使用OfType,将集合根据泛型进行进一步的细分。当然,如果采用Object的封包拆包也可以达到同样效果,但是效率上就会差很多了。

 

 进阶用法

我们知道,映射是计算机编程的一种重要思想,映射字典提供了不同系统间交互的可能,接下来我们将采用OfType来动态获取映射字典。

假设现在有三家公司的映射字典如下:

 

  public static class DicBook
    {
        public static Dictionary<string, string> CompanyADic { get; } = new Dictionary<string, string>
        {
            {"xingming","name" },
            {"nianling","age" },
        };
        public static Dictionary<string, string> CompanyBDic { get; } = new Dictionary<string, string>
        {
            {"xm","name" },
            {"xl","age" },
        };
        public static Dictionary<string, string> CompanyCDic { get; } = new Dictionary<string, string>
        {
            {"name","name" },
            {"age","age" },
        };
    }

建立这三个映射的相关类,作为动态解析的依据

    public class ComapnyA { }
    public class ComapnyB { }
    public class ComapnyC { }

 

 那么我们如何使用OfType来动态解析映射关系呢?请直接看下面的代码

 

        public interface IPropertyMapping
        {
        }
        public class PropertyMapping<TSource> : IPropertyMapping
        {
            public Dictionary<string, string> MappingDictionary { get; set; }
            public PropertyMapping(Dictionary<string, string> mappingDictionary)
            {
                MappingDictionary = mappingDictionary;
            }
        }
        private static List<IPropertyMapping> propertyMappings = new List<IPropertyMapping>();
        static void Main(string[] args)
        {
            propertyMappings.Add(new PropertyMapping<ComapnyA>(DicBook.CompanyADic));
            propertyMappings.Add(new PropertyMapping<ComapnyB>(DicBook.CompanyADic));
            propertyMappings.Add(new PropertyMapping<ComapnyC>(DicBook.CompanyADic));

            var a = propertyMappings.OfType<PropertyMapping<ComapnyA>>().ToList(); //输出{"xingming","name" },{"nianling","age" }
            var b = propertyMappings.OfType<PropertyMapping<ComapnyB>>().ToList(); //Output DicBook.CompanyBDic Info 

var c = propertyMappings.OfType<PropertyMapping<ComapnyC>>().ToList(); //Output DicBook.CompanyCDic Info
}

上面代码,PropertyMapping 包含一个字典类型,继承自 IPropertyMapping ,同时定义了一个集合类型为 IPropertyMapping propertyMappings 集合

通过Add方法添加具体字典,并且传入类的泛型,这样就可以通过OfType按照添加时的类型来解析出映射字典了。

看到这里,也许有人觉得搞了这么多,还不如直接使用DicBook的静态类来的方便。但是,因为CompanyA ComapnyB ComapnyC 类型可以通过反射获得,所以,这样做实现了动态获取。

 

接下来,我将封装到一个服务类中,采用IOC容器的注册,方便以后的复用

namespace MyApp.Services
{
    public interface IPropertyMapping
    {
    }
    public class PropertyMapping<TSource> : IPropertyMapping
    {
        public Dictionary<string, string> MappingDictionary { get; set; }
        public PropertyMapping(Dictionary<string, string> mappingDictionary)
        {
            MappingDictionary = mappingDictionary;
        }
    }
    public interface IPropertyMappingService
    {
        Dictionary<string, string> GetPropertyMapping<TSource>();
    }
    public class PropertyMappingService : IPropertyMappingService
    {
        private IList<IPropertyMapping> _propertyMappings { get; set; }
        public PropertyMappingService(IList<IPropertyMapping> propertyMappings)
        {
            _propertyMappings = propertyMappings;
        }
        public Dictionary<string, string> GetPropertyMapping<TSource>()
        {
            if (_propertyMappings == null)
            {
                throw new ArgumentNullException(nameof(_propertyMappings));
            }
            //获得匹配的映射对象
            var matchingMapping =
                _propertyMappings.OfType<PropertyMapping<TSource>>();

            if (matchingMapping.Count() == 1)
            {
                return matchingMapping.First().MappingDictionary;
            }
            else
            {
                throw new Exception(
                    $"Cannot find only one exact property mapping instance for<{typeof(TSource)}>"
                    );
            }
        }
    }
}

 

注册到ICO

      public void ConfigureServices(IServiceCollection services)
        {
            IServices.PropertyMappingService propertyMappingService = new IServices.PropertyMappingService(
                new List<IPropertyMapping>() 
                {
                 new PropertyMapping<ComapnyA>(DicBook.CompanyADic),
                 new PropertyMapping<ComapnyB>(DicBook.CompanyADic),
                 new PropertyMapping<ComapnyC>(DicBook.CompanyADic)
                }
            
             );
            services.AddSingleton<IServices.IPropertyMappingService>(propertyMappingService);
        }

调用

    public CalculateController(Services.IPropertyMappingService propertyMappingService)
        {
            _propertyMappingService = propertyMappingService;

            var aDic = _propertyMappingService.GetPropertyMapping<ComapnyA>();  //输出{"xingming","name" },{"nianling","age" }

var bDic = _propertyMappingService.GetPropertyMapping<ComapnyB>();
            var cDic = _propertyMappingService.GetPropertyMapping<ComapnyC>();
        }

 

 

 

翻译 朗读 复制 正在查询,请稍候…… 重试 朗读 复制 复制 朗读 复制 via 百度翻译

 

翻译 朗读 复制 正在查询,请稍候…… 重试 朗读 复制 复制 朗读 复制 via 百度翻译

posted on 2021-08-23 14:19  鲁广广  阅读(708)  评论(0编辑  收藏  举报

导航