c# 利用Attribute 添加函数执行条件 解除工厂if else 或 switch case的 判断

先写个草稿

示例等后面再加上去 先把灵感记下来

代码下载地址:https://download.csdn.net/download/sinat_30224769/10632514


        [AttributeUsage(AttributeTargets.Method, Inherited = false)]
        [System.Runtime.InteropServices.ComVisible(true)]

        public class CaseRange : Attribute
        {
            public Func<bool> Case { get; set; }
            public CaseRange()
            {
                throw new Exception("必须添加函数执行的条件或范围");
            }
            /// <summary>
            /// 给方法添加执行条件
            /// </summary>
            /// <param name="Case"></param>
            public CaseRange(Func<bool> Case)
            {
                this.Case = Case;
            }
        }

引用:策略模式: https://blog.csdn.net/u012124438/article/details/70039943/

----------------------------------------------------------------分割线--------------------------------------------------------

时间是检验真理的唯一标准

现在以支付为例

支付类中有 支付宝、微信

各有方法 主扫、被扫、获取自己的名称(测试打印当前类信息)

第一需要Attribute类

目前先做类标记 解决 工厂模式 if else

起个名字就叫做(类枚举特性标记)

    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class ClassEnumConditionAttribute : Attribute
    {
        public PayTypeEnum EnumCondition { get; set; }
        /// <summary>
        /// 给方法添加执行条件
        /// </summary>
        /// <param name="Case"></param>
        public ClassEnumConditionAttribute(PayTypeEnum EnumCondition)
        {
            this.EnumCondition = EnumCondition;
        }
    }

第二开始构造个接口

和实现具体的类

构造接口

  public interface IPayMentBase
    {
        string WhoAmI();
        bool MainPay();
        bool ScanPay(string QRCode);
    }

实现类 这里要记住命名空间尽量使用同一个 可以提高效率


namespace StrategicFactory.Model.PayMent
{
    [ClassEnumCondition(PayTypeEnum.AliPay)]
    public class AliPay : IPayMentBase
    {
        public bool MainPay()
        {
            return true;
        }

        public bool ScanPay(string QRCode)
        {
            return true;
        }

        public string WhoAmI()
        {
            return "AliPay";
        }
    }
}

namespace StrategicFactory.Model.PayMent
{
    [ClassEnumCondition(PayTypeEnum.WeiXinPay)]
    public class WeixinPay : IPayMentBase
    {
        public bool MainPay()
        {
            return true;
        }

        public bool ScanPay(string QRCode)
        {
            return true;
        }

        public string WhoAmI()
        {
            return "WeixinPay";
        }
    }
}

为了调用方便 起一个 枚举类作为 选择的条件   这里就相当于原来的 ifelse 需要判断的地方

  public enum PayTypeEnum
    {
        AliPay,
        WeiXinPay
    }

最关键的就是 筛选了

第一个方法是用来测试的方法

第二个 因为要睡觉了 所以有空在写(应该还可以继续简化,减少内部干扰减少依赖)

 public class PayMentFactory<T> where T : Attribute
    {
        /// <summary>
        /// 获取实例 定义式(返回具体对象)
        /// </summary>
        /// <param name="Case"></param>
        /// <returns></returns>
        public IPayMentBase GetPayMent(Func<T, bool> Case)
        {
            var Namespace = "StrategicFactory.Model.PayMent";//减少搜索的数据量定位类更快(可外部传入)
            //var xx = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.Namespace == Namespace).ToArray();
            //搜索命名空间中的类 
            //如果是外部DLL Assembly.Load("namespace").GetTypes();
            var patment = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.Namespace == Namespace).FirstOrDefault(
                x =>
                {
                    var tempAttrr = Attribute.GetCustomAttribute(x, typeof(T));
                    if (tempAttrr == null) return false;
                    if (!(tempAttrr is T)) return false;
                    return Case(tempAttrr as T);
                }
            );
            if (patment == null)
            {
                throw new Exception("错误");
            }
            dynamic obj = patment.Assembly.CreateInstance(patment.FullName);
            return (IPayMentBase)obj;
        }

        /// <summary>
        ///  获取实例 解耦式 返回object对象 在外部转化 
        /// </summary>
        /// <param name="Case"></param>
        /// <param name="Namespace">减少搜索的数据量定位类更快(可外部传入)</param>
        /// <returns></returns>
        public object GetPayMent2(Func<T, bool> Case, string Namespace = "")
        {
            //搜索命名空间中的类 
            //如果是外部DLL Assembly.Load("namespace").GetTypes();
            var patment = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.Namespace == Namespace).FirstOrDefault(
                x =>
                {
                    var tempAttrr = Attribute.GetCustomAttribute(x, typeof(T));
                    if (tempAttrr == null) return false;
                    if (!(tempAttrr is T)) return false;
                    return Case(tempAttrr as T);
                }
            );
            if (patment == null)
            {
                throw new Exception("错误");
            }
            dynamic obj = patment.Assembly.CreateInstance(patment.FullName);
            return obj;
        }
    }

都准备好了 那就尝试着调用一下


namespace StrategicFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            PayMentFactory<ClassEnumConditionAttribute> tempFactory = new PayMentFactory<ClassEnumConditionAttribute>();
            var Pay = tempFactory.GetPayMent(x => x.EnumCondition == PayTypeEnum.AliPay);
            Console.WriteLine(Pay.WhoAmI());
            Pay = tempFactory.GetPayMent(x => x.EnumCondition == PayTypeEnum.WeiXinPay);
            Console.WriteLine(Pay.WhoAmI());
            Console.ReadLine();
        }
    }
}

调用成功===

这里提一下,调用工厂方法的地方是不知道具体传入的是什么类型的

而是进入以后通过 条件判断选择 return new AliPay() 还是 return new WeixinPay();

具体来说因该是 Reflection配合 Attribute 解决的 ,不过感觉反射还是有一定风险的,在处理结果的时候判断要全面

---

接下来将尝试 方法的 Attribute消除 ifelse

--

那么今天就先休息了~

猜你喜欢

转载自blog.csdn.net/sinat_30224769/article/details/82144688