欧美V国产V亚洲V日韩九九_国产偷V国产偷V亚洲高清_蜜桃精品免费久久久久影院_亚洲男同志Gay 片可播放

C#泛型編程(cheng)已經(jing)深入人心了。為(wei)什么又(you)提出C#模(mo)板(ban)編程(cheng)呢?因為(wei)C#泛型存在一(yi)些(xie)(xie)局限性,突(tu)破(po)這些(xie)(xie)局限性,需要使用(yong)C#方(fang)式的(de)模(mo)板(ban)編程(cheng)。由于(yu)C#語法、編譯器、IDE限制(zhi),C#模(mo)板(ban)編程(cheng)沒有C++模(mo)板(ban)編程(cheng)使用(yong)方(fang)便(bian),但是,仍(reng)然可(ke)以解決(jue)一(yi)些(xie)(xie)問(wen)題。

 

下面先看(kan)C#泛(fan)型編程的兩個限制:

(1)類型約束問題。

C#泛型(xing)的類型(xing)約(yue)束是(shi)個很嚴重的問(wen)題。

假設(she)需要寫一個泛(fan)型(xing)方(fang)(fang)法(fa),這(zhe)個方(fang)(fang)法(fa)有2個參(can)數(shu),然后方(fang)(fang)法(fa)返(fan)回結果是這(zhe)兩(liang)個參(can)數(shu)的和。

這樣的泛(fan)型(xing)方法無法直(zhi)接(jie)實(shi)現。因(yin)為Byte,Int32等等并沒有公共接(jie)口。

沒有公共(gong)接(jie)口,但又想借助泛型來(lai)節省代(dai)碼(ma),減少維護量(liang)。怎(zen)么辦呢?

我之前寫(xie)過(guo)2篇博客《》、《》,通(tong)過(guo)Ducking Typing來實(shi)現,但這種實(shi)現方式不自然,且性能(neng)低下,只(zhi)適合對性能(neng)不敏感的場(chang)景(jing)。

(2)泛型(xing)指針問(wen)題。

泛型程(cheng)序中無(wu)法使(shi)用泛型指針,因為編譯器編譯時無(wu)法知道具(ju)體類(lei)型的Size,這對(dui)寫unsafe代(dai)碼是很大的限制(zhi)。

 

因此,我們需要C#模(mo)板編程。C#模(mo)板編程說起來很簡單,它(ta)(ta)借助的是C#的一個語法——Using T0=T1。它(ta)(ta)沒有C++那(nei)么自(zi)然,因為它(ta)(ta)缺乏(fa)C/C++源(yuan)文件的Include機制(zhi)。你可以將整塊的文件在(zai)不(bu)同的類之間進(jin)行復制(zhi)和(he)粘(zhan)帖(tie)(tie)。雖然復制(zhi)和(he)粘(zhan)帖(tie)(tie)是一大(da)邪惡,但總比復制(zhi)/粘(zhan)帖(tie)(tie)/替(ti)換(huan)要好很多。

下面是C#模板編程的一個(ge)重要應用——圖像處(chu)理的空間(jian)線性濾(lv)(lv)波。關于空間(jian)線性濾(lv)(lv)波可參見各種圖像處(chu)理的書,這里不(bu)做介紹。

我們假定(ding)圖像是一個(ge)(ge)(ge)(ge)泛型類(lei)(lei)(lei)Image<T0>,這(zhe)里(li)(li)T代表每(mei)一個(ge)(ge)(ge)(ge)像素的(de)(de)存(cun)(cun)(cun)儲類(lei)(lei)(lei)型。可以是Byte,Short,Int32,Int64,Single,Double等(deng)。然后,核是一個(ge)(ge)(ge)(ge)泛型類(lei)(lei)(lei),Kernel<T1>,這(zhe)里(li)(li)還有(you)第三(san)個(ge)(ge)(ge)(ge)泛型類(lei)(lei)(lei),就(jiu)是用于存(cun)(cun)(cun)放中間(jian)(jian)(jian)數(shu)據的(de)(de)Image<T2>。為什(shen)么需要T2呢?假如T0是Byte,T1是帶有(you)Scale的(de)(de)Int32(如,Scale=9,每(mei)個(ge)(ge)(ge)(ge)元素值=1的(de)(de)3*3矩陣),計(ji)算(suan)的(de)(de)中間(jian)(jian)(jian)結果會超出Byte的(de)(de)最大值,需要一個(ge)(ge)(ge)(ge)不同類(lei)(lei)(lei)型緩(huan)存(cun)(cun)(cun)來存(cun)(cun)(cun)儲這(zhe)個(ge)(ge)(ge)(ge)中間(jian)(jian)(jian)數(shu)據。

只用泛(fan)型(xing)的話,解決不了這個(ge)問題(ti)。第一(yi)點,Byte,Short,Int32,Int64,Single,Double之間未實現共同接口(kou);第二點,為提升性能,Image<T>采(cai)用非托管內存實現,使用指(zhi)針進(jin)行操作,而泛(fan)型(xing)中無法使用泛(fan)型(xing)指(zhi)針。

使(shi)用C#模板可(ke)(ke)以(yi)解決這個問(wen)題(ti)——代碼照舊,只是在(zai)頭部寫下(xia):Using T0=XXX;Using T1=XXX;Using T2=XXX;即可(ke)(ke)。

由于(yu)欠缺源代碼的(de)(de)Include機制(zhi)(zhi),當要(yao)編寫新的(de)(de)濾波器(qi)時,需(xu)要(yao)把相同的(de)(de)代碼復制(zhi)(zhi)過去,然(ran)后更(geng)改頭部(bu)的(de)(de)Using ……。但(dan)無論如何,這樣使(shi)用,還是比在代碼中(zhong)直接寫明類型,然(ran)后復制(zhi)(zhi)、粘帖、替換新類型的(de)(de)可(ke)讀性以及可(ke)維護性要(yao)好。

如果.Net允(yun)許(xu)源代碼的(de)Include,C#的(de)模(mo)板編(bian)程將變(bian)得更為流暢(比起C++還是欠缺(que)很多)。不知道等后續.Net版(ban)本開放編(bian)譯服務之后,會不會有更優雅的(de)寫法。

下(xia)面是我隨便(bian)寫下(xia)的一(yi)段(duan)對圖像(xiang)進行空間線性濾波的代(dai)碼(ma)(ma)(不要看具體(ti)算法,具體(ti)算法是極端(duan)錯誤的,且(qie)不完(wan)整的,只用看看編碼(ma)(ma)風格就(jiu)行了(le),寫這段(duan)代(dai)碼(ma)(ma)只為(wei)驗證這種編程模式的優點和缺點):

using System;
using System.Collections.Generic;
using System.Text;

using T = System.Byte;
using CacheT = System.Int32;
using K = System.Int32;

namespace Orc.SmartImage.UnmanagedImage
{
    public static class FilterHelper
    {
        public unsafe static UnmanagedImage<T> Filter(this UnmanagedImage<T> src, FilterKernel<K> filter)
        {
            K* kernel = stackalloc K[filter.Length];

            Int32 srcWidth = src.Width;
            Int32 srcHeight = src.Height;
            Int32 kWidth = filter.Width;
            Int32 kHeight = filter.Height;

            T* start = (T*) src.StartIntPtr;
            T* lineStart = start;
            T* pStart = start;
            T* pTemStart = pStart;
            T* pT;
 &nbsp;          Int32* pK;

            for (int c = 0; c < srcWidth; c++)
            {
                for (int r = 0; r < srcHeight; r++)
                {
                    pTemStart = pStart;
         ;           pK = kernel;

                    Int32 val = 0;
                    for (int kc = 0; kc < kWidth; kc++)
                    {
                        pT = pStart;
                        for (int kr = 0; kr < kHeight; kr++)
                        {
                            val += *pK * *pT;
                            pT++;
                            pK++;
 &nbsp;                      }

                        pStart += srcWidth;
          &nbsp;         }

                    pStart = pTemStart;
                    pStart++;
      &nbsp;         }

                lineStart += srcWidth;
                pStart = lineStart;
            }
            return null;
        }
    }
}

 

是(shi)不是(shi)很像(xiang)模板編程呢?