|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
可怜的程序员,还是逃不出移植的命运!话说微信公家账号上的第一期有奖征答举动公布至今已有两周工夫,不外介入人数寥寥,是太难,仍是奖品不敷吸惹人?人人要多介入,我们才干临时互动嘛。如今我就对第一期的标题“逆泛型实行器”举行复杂解说吧,实在这题很复杂,今后相似难度的标题大概会放在“疾速问答”环节中。话说第一期的疾速问答还在举行当中,人人加油。
参考解答
所谓“逆泛型”,即我们但愿能够在一个泛型操纵中,只对特定的范例组合举行呼应。比方:- publicclassTicksToDateTimeCaller{privatestaticDateTimeTicksToDateTime(longticks){returnnewDateTime(ticks);}publicTResultCall<T,TResult>(Targ){return(TResult)(object)TicksToDateTime((long)(object)arg);}}
复制代码 以上代码会发生无谓的代码转换及装箱拆箱操纵(只管它们在Release形式下会被优化失落),为了不这点,我们能够这么做:- publicclassTicksToDateTimeCaller{privatestaticclassCache<T,TResult>{publicstaticFunc<T,TResult>Call;}privatestaticDateTimeTicksToDateTime(longticks){returnnewDateTime(ticks);}staticTicksToDateTimeCaller(){Cache<long,DateTime>.Call=TicksToDateTime;}publicTResultCall<T,TResult>(Targ){returnCache<T,TResult>.Call(arg);}}
复制代码 我们创立了一个外部类Cache,它起到了缓存的感化。.NET泛型的奇奥的地方便在于其“静态”及“辨别”。“静态”在于它能够于运转时举行详细化(相对C++里的“静态”),不外今朝的成绩不触及这点。而“辨别”则意味着分歧的详细泛型参数,在.NET中都是分歧的范例,具有完整分别的元数据,比方办法表(MethodTable),和静态字段等等。
这里我们便当用了这一点。因为我们只针对特定范例组合的Cache范例设置其Call字段,因而其他的范例组合天然就会间接抛出非常了。值得注重的是,也恰是因为“辨别”,分歧的详细化范例具有分歧的元数据。因而,假设这个办法会遭受大批不法挪用的话,最幸亏会见Cache<T,TResult>之行进行范例判别,并间接抛出非常,如许能够制止发生无用的元数据。
之前有人问,为何不成以用Java来完成呢?要晓得.NET的泛型岂是Java的“伪泛型”能够等量齐观的。
推行用法
这类做法还能够推行开来。比方在我今朝的项目顶用到一个第三方类库,它供应了一条笔记录,我们能够读取其各字段的值,API以下方IRecord接口所示:- publicinterfaceIRecord{stringGetString(stringfield);intGetInt(stringfield);longGetLong(stringfield);}
复制代码 但这个API在利用上其实不友爱,我们更希冀能够有一个通用的Get<T>办法,能够用来读取各类范例。因而我们即可以云云来编写一个扩大办法:- publicstaticclassRecordExtensions{privatestaticclassCache<T>{publicstaticFunc<IRecord,string,T>Get;}staticRecordExtensions(){Cache<string>.Get=(record,field)=>record.GetString(field);Cache<int>.Get=(record,field)=>record.GetInt(field);Cache<long>.Get=(record,field)=>record.GetLong(field);}publicstaticTGet<T>(thisIRecordrecord,stringfield){returnCache<T>.Get(record,field);}}
复制代码 现实上,利用Lambda表达式会天生分外的直接挪用,我们间接利用CreateDelegate办法能够进一步下降开支。固然,这属于极小的优化,但既然不贫苦,又何乐而不为呢:- publicstaticclassReflectionExtensions{publicstaticTDelegateCreateDelegate<TDelegate>(thisMethodInfomethod){return(TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate),method);}}publicstaticclassRecordExtensions{privatestaticclassCache<T>{publicstaticFunc<IRecord,string,T>Get;}staticRecordExtensions(){Cache<string>.Get=typeof(IRecord).GetMethod("GetString").CreateDelegate<Func<IRecord,string,string>>();Cache<int>.Get=typeof(IRecord).GetMethod("GetInt").CreateDelegate<Func<IRecord,string,int>>();Cache<long>.Get=typeof(IRecord).GetMethod("GetLong").CreateDelegate<Func<IRecord,string,long>>();}publicstaticTGet<T>(thisIRecordrecord,stringfield){returnCache<T>.Get(record,field);}}
复制代码 作为一个次要事情是写基本代码给他人用的人,我还真堆集了很多编写API的风趣履历,无机会渐渐分享。这里先来一发,那就是利用out关头字来削减范例信息——谁让C#只能经由过程参数举行范例揣度呢?- publicstaticclassReflectionExtensions{publicstaticvoidCreateDelegate<TDelegate>(thisMethodInfomethod,outTDelegateresult){result=(TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate),method);}}publicstaticclassRecordExtensions{privatestaticclassCache<T>{publicstaticFunc<IRecord,string,T>Get;}staticRecordExtensions(){typeof(IRecord).GetMethod("GetString").CreateDelegate(outCache<string>.Get);typeof(IRecord).GetMethod("GetInt").CreateDelegate(outCache<int>.Get);typeof(IRecord).GetMethod("GetLong").CreateDelegate(outCache<long>.Get);}publicstaticTGet<T>(thisIRecordrecord,stringfield){returnCache<T>.Get(record,field);}}
复制代码 再留个成绩:参考解答中的TicksToDateTime办法是静态办法,那假设我们必要挪用的是一个实例办法又该怎样做?注重,这里不同意在每一个对象的机关函数里创立自力的托付对象,由于这个操纵的开支太年夜。创立一个静态的对象不外是一次性事情,而创立大批的对象则会形成非常可不雅的开支了。
没想出来?触类旁通的才能必需增强啊。
其他谜底
这个成绩只收到的谜底寥寥可数。有的对照无厘头,比方:
我以前很喜欢Serv-U,自从它用net网页编程重写之后我就再也没用过,实在是太慢了,我宁可用IIS搭建FTP,虽然IIS搭建FTP在权限管理上很不灵活。 |
|