对《以非泛型方式调用泛型方法》一文的探讨


看了 Kanas.Net 的  以非泛型方式调用泛型方法 ,思考了一下午。

(一)简化

Kanas.Net 对比的5种方案中,1、2、5 三种方案均需要在编译时指定所使用的类型,因此并未解决问题。方案3性能较低,方案4是有效方案:

·定义泛型委托;
·定义非泛型接口;
·实现这个接口;
·通过泛型委托获取非泛型接口的实现。

感觉方案4将问题复杂化了,这里采用委托用处不大,平添加许多复杂性。

我先前错误认为.net中的范型方法是在运行时才实例化的,装配脑袋 指出是在编译期实例化的,用reflector查看代码,正如装配脑袋所言,范型方法是在编译器实例化。因此,要解决以非范型方式调用范型方法的关键就在于在运行期产生指定类型范型方法。Kanas.Net 的方案4既是这个策略:
(1)申明一个非范型接口,用来持有运行期生成的方法,供后期调用;
(2)采用一个范型类,继承非范型接口
(3)一个方法,能够根据指定的类型名称,创建相应的范型类。

采用这种策略,更简洁的实现是引入helper:

 1 None.gif      public   interface  IServerClassHelper
 2 ExpandedBlockStart.gifContractedBlock.gif     dot.gif {
 3InBlock.gif        void InvokeAdd(object obj, object list);
 4ExpandedBlockEnd.gif    }

 5 None.gif
 6 None.gif     public   class  ServerClass
 7 ExpandedBlockStart.gifContractedBlock.gif     dot.gif {
 8InBlock.gif        public void Add<T>(T obj, ICollection<T> c)
 9ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
10InBlock.gif            c.Add(obj);
11ExpandedSubBlockEnd.gif        }

12InBlock.gif
13InBlock.gif        public IServerClassHelper CreateHelper(Type T)
14ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
15InBlock.gif            Type helperType = typeof(ServerClassHelper<>).MakeGenericType(T);
16InBlock.gif            IServerClassHelper helper = Activator.CreateInstance(helperType, thisas IServerClassHelper;
17InBlock.gif            return helper;
18ExpandedSubBlockEnd.gif        }

19InBlock.gif
20InBlock.gif        private sealed class ServerClassHelper<T> : IServerClassHelper
21ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
22InBlock.gif            private ServerClass m_server;
23InBlock.gif
24InBlock.gif            public ServerClassHelper(ServerClass server)
25ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
26InBlock.gif                m_server = server;
27ExpandedSubBlockEnd.gif            }

28InBlock.gif
29InBlock.gif            public void InvokeAdd(object obj, object list)
30ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
31InBlock.gif                m_server.Add<T>((T)obj, (ICollection<T>)list);
32ExpandedSubBlockEnd.gif            }

33ExpandedSubBlockEnd.gif        }

34ExpandedBlockEnd.gif    }

使用:

1 None.gif             ClientClassA a  =   new  ClientClassA();
2 None.gif            ICollection < ClientClassA >  ca  =   new  List < ClientClassA > ();
3 None.gif            String TypeString  =   " GenericMethodTest.ClientClassA " ;
4 None.gif            IServerClassHelper helper  =  server.CreateHelper(Type.GetType(TypeString));
5 None.gif            helper.InvokeAdd(a, ca);

性能测试:

1 : 2.09

(二)改进

上面方案使用起来还是比较复杂,首先需要获得一个helper,然后调用helper的相应方法。还是不够直接。继续改进吧,改进成<以非泛型方式调用泛型方法>一文开始所述接口:

Add(Type type, Object obj, Object c)。

以下是代码:

 1 None.gif      public   class  ServerClass
 2 ExpandedBlockStart.gifContractedBlock.gif     dot.gif {
 3InBlock.gif        private static ICollection<IServerClassHelper> m_helpers = new List<IServerClassHelper>();
 4InBlock.gif
 5InBlock.gif        public void Add<T>(T obj, ICollection<T> c)
 6ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 7InBlock.gif            c.Add(obj);
 8ExpandedSubBlockEnd.gif        }

 9InBlock.gif
10InBlock.gif        public void Add(Type type, Object obj, Object c)
11ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
12InBlock.gif            GetHelper(type).InvokeAdd(obj, c);
13ExpandedSubBlockEnd.gif        }

14InBlock.gif
15InBlock.gif        private IServerClassHelper GetHelper(Type T)
16ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
17InBlock.gif            foreach(IServerClassHelper h in m_helpers)
18ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
19InBlock.gif                if (h.Equals(T)) return h;
20ExpandedSubBlockEnd.gif            }

21InBlock.gif            IServerClassHelper helper = CreateHelper(T);
22InBlock.gif            m_helpers.Add(helper);
23InBlock.gif            return helper;
24ExpandedSubBlockEnd.gif        }

25InBlock.gif
26InBlock.gif        private IServerClassHelper CreateHelper(Type T) 
27ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
28InBlock.gif            Type clientType = typeof(ServerClassHelper<>).MakeGenericType(T);
29InBlock.gif            IServerClassHelper helper = Activator.CreateInstance(clientType, this, T) as IServerClassHelper;
30InBlock.gif            return helper;
31ExpandedSubBlockEnd.gif        }

32InBlock.gif
33InBlock.gif        private interface IServerClassHelper : IEquatable<Type>
34ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
35InBlock.gif            void InvokeAdd(object obj, object list);
36ExpandedSubBlockEnd.gif        }

37InBlock.gif
38InBlock.gif        private sealed class ServerClassHelper<T> : IServerClassHelper
39ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
40InBlock.gif            private ServerClass m_server;
41InBlock.gif            private Type m_type;
42InBlock.gif
43InBlock.gif            public ServerClassHelper(ServerClass server, Type type)
44ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
45InBlock.gif                if (server == nullthrow new ArgumentNullException();
46InBlock.gif                if (type == nullthrow new ArgumentNullException();
47InBlock.gif                m_server = server;
48InBlock.gif                m_type = type;
49ExpandedSubBlockEnd.gif            }

50InBlock.gif
51InBlock.gif            public void InvokeAdd(object obj, object list)
52ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
53InBlock.gif                m_server.Add<T>((T)obj, (ICollection<T>)list);
54ExpandedSubBlockEnd.gif            }

55InBlock.gif
56ContractedSubBlock.gifExpandedSubBlockStart.gif            IEquatable 成员#region IEquatable<Type> 成员
57InBlock.gif
58InBlock.gif            public bool Equals(Type other)
59ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
60InBlock.gif                if (other == nullreturn false;
61InBlock.gif                return m_type.Equals(other);
62ExpandedSubBlockEnd.gif            }

63InBlock.gif
64ExpandedSubBlockEnd.gif            #endregion

65ExpandedSubBlockEnd.gif        }

66ExpandedBlockEnd.gif    }

使用:

1 None.gif             String TypeString  =   " GenericMethodTest.ClientClassA " ;
2 None.gif            Type clientType  =  Type.GetType(TypeString);
3 None.gif            server.Add(clientType, a, ca);
4 None.gif

好了,这下简单了,复杂的都封装到ServerClass的内部了。

性能:

1 :  6

(三)消除问题

从以上实现可以看出,关键问题在于将范型方法映射为不带范型方法范型类,然后在运行期实例化。何必这么复杂呢,为什么不将 ServerClass申明为一个范型类呢?这样又存在另外一个问题,如何在运行期持有ServerClass<T>类对象呢?要解决这个问题,又需要申明非范型接口。

不过再仔细考虑,到底需不需要非泛型方式调用泛型方法?

将所需传入的类型叫做ClientClass,分析两种应用场景:

(1)ServerClass 知道 ClientClass 的存在,那么在编译时就可以进行推演。
(2)ServerClass 不知道 ClientClass 的存在,但是在内存中,总存在一种类型,ClientClass以这种类型被持有,而ServerClass又知道这种类型的存在,ServerClass可以以该类型为类型参数,在编译期就实例化。这种类型一般是ServerClass那边定义的接口。假如 ClientClass 不能实现该接口,包装一下子嘛!

所以我觉得,最好不要以非范型方式调用范型方法.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值