2008年8月23日 星期六

出現「這個安裝不支援這種專案類型」?(8.23)

由於要承接別人案子的緣故
所以我的同夥將他的程式整包丟給我
那想當然爾,就一如往常的要將專案建置起來
沒想到,出乎意料的搞不定
出現了這樣的錯誤訊息,讓我苦惱一時
後來又看到這個專案裡的程式
跟我們一般的不同,就是一支網頁不只有
*.aspx
*.aspx.cs
又多了
*.aspx.designer.cs
這樣的東西
這一下這支程式裡的內容,似乎只是介紹控制項而已。
後來上網查了一下
原來是因為此專案在設計時
已經安裝了VS2005 SP1 的 Service Pack
所在這個專案在新增時,就會另外出現這樣的程式(*.aspx.designer.cs
而原本尚未安裝SP1的我,遇到這種不認識的程式
就會發生錯誤,專案自然就開啟不了
所以,記得請先安裝VS2005 SP1 再開專案吧。

2008年8月7日 星期四

物件導向程式設計_介面(Interface)(8.6)

何謂介面(Interface):
在google上,的確有著非常多相關於介面(Interface)的討論、說明。
不曉得是不是本人智商過低,亦或是人家講的不清楚? 我是都有看沒有懂。
不過,看大家在都可以在各論壇討論得沸沸騰騰,所以,猜想答案應該是前者吧(本人智商過低)。
但是,畢竟用一種說法,並不代表可以說懂每一個人嘛,不然,哪來的「因材施教」呢?
也幸好,本人並非「朽木不可雕也」,看了一堆人的說法,總算是有點心得。
其實,透過字面上,我們也可以看得出來「介面(Interface)」是什麼東西。
就是某個東西,要操控、使用另一個東西時,中間的橋梁,
就像我們在使用電腦時,會有一個介面(window畫面),來指引你使用,
我們在看電視轉台時,會有個搖控器或是選台的按鈕讓你來轉台。
這邊主要的觀念是想說,「介面(Interface)」主要就是構成二者互動的橋梁。
有了這個概念後,我們把概念帶到程式這邊來:
介面(Interface)就是「程式碼」與「類別(Class)」之間的橋梁。
當然,我們在寫程式時,也不見得會採取介面(Interface)的方法,
我們會直接「程式碼--->類別」,並不會「程式碼--->介面--->類別」的流程。
只是說,若使用介面(Interface)的話,它們的關係,是這樣子的。
介面(Interface)的使用:(C#)
interface IHardDisk
{
void setDefault(); //設定硬碟容量的起始值
bool compareHD(int HD); //比較看哪個容量大
int HD_gigabyte{ set;get;} //設定/取得硬碟容量
public void errtest();
}
小提醒:
  1. 一般習慣,在命名介面(Interface)時,都以「I」為開頭表示Interface。
  2. 在定義介面(Interface)時,裡面的方法,屬性都只「定義」而已,並未真正的實作內容
  3. 由於,此為測試,所以真正在應用時,請適時地加上「Public」修飾詞。ex: Public interface IHardDisk {...}。
  4. 上面紅色字體,表示為錯誤的使用方法:不用加上「Public」修飾詞.
看完了如何定義一個介面(Interface)後,我們接著看範例。
介面(Interface)範例:
範例說明(實作):
  1. 定義介面(IHardDisk)
  2. 利用類別(HardDisk)實作介面
  3. 程式中,一改以往呼叫類別的方法,改以呼叫介面
  4. 使用該介面的各屬性、方法
小提醒:
  1. 在實作介面時,該介面所定義的方法、屬性,在類別那,都要一一實作
  2. 在實作介面時,每個「方法」都請加上修飾詞「Public
  3. 程式宣告時「IHardDisk ComputerHD=new HardDisk() ; 」,後面是 new 一個類別。
程式碼:
---------------------------------------------
interface IHardDisk
{
void setDefault(); //設定硬碟容量的起始值
bool compareHD(int HD); //比較看哪個容量大
int HD_gigabyte{ set;get;} //設定/取得硬碟容量

}
class HardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來
int hd_gigabyte;//宣告一個變數來存取硬碟容量的值

public void setDefault()//實作「設定起始值」的方法
{
hd_gigabyte = 520;
}

public bool compareHD(int HD)//實作「比較大小」的方法
{
if (HD > hd_gigabyte){return true;}
else{return false;}
}

public int HD_gigabyte //實作「取得/設定容量」的屬性
{
get { return hd_gigabyte; }
set {hd_gigabyte=value;}
}
}

protected void Page_Load(object sender, EventArgs e)
{
IHardDisk ComputerHD=new HardDisk() ; //宣告
ComputerHD.setDefault(); //設定硬碟容量的預設值
Response.Write(ComputerHD.HD_gigabyte); //取得硬碟容量
Response.Write(ComputerHD.compareHD(567)); //比較大小

}
--------------------------------------------
為何要使用介面(Interface):
看了以上的範例,會有個想法:這種作法,比我直接呼叫類別的方法還要繁瑣
我直接將方法寫在類別裡,再呼叫類別使用就好啦!(「程式碼--->類別」)
何必要這麼麻煩,還透過介面,多了一道手續(「程式碼--->介面--->類別」)
沒錯,藉由以上的範例,的確看不出用介面(Interface)的好處。
然而,使用介面的好處在於「泛用」。
所謂的「泛用」或許可以解釋成「廣泛地使用」,
也就是說,我們只要使用介面,就可以使用不同的類別(前提為,該類別必須實作該介面)
範例說明:(實作)
  1. 相同地我們定義一個介面(Interface)
  2. 另外,我們產生兩個類別一個適用於小型硬碟(miniHardDisk),另一個適用於大型硬碟(bigHardDisk)
  3. 兩者也都實作了IHardDisk的介面
  4. 再來,我們又新增了一個類別,這個類別裡,定義的方法為回傳一個介面的型態(將來都實作產生這個類別)
  5. 在程式碼中,可看到,我們在Computer的類別裡,我們目前是使用「小型硬碟」
  6. 在Page_Load中,我們輸出了介面,及二類別的資料
程式重點:
  1. 程式中,我們目前是使用「小型硬碟」,若突然要改成「大型硬碟」時,我們只需更動,Computer的類別即可,程式碼,完全不用更動
  2. 將類別中的「miniHardDisk cc = new miniHardDisk();」,改成「bigHardDisk cc = new bigHardDisk ();」
程式碼:
======================================

interface IHardDisk
{
void setDefault();//設定硬碟容量的起始值
bool compareHD(int HD);//比較看哪個容量大
int HD_gigabyte { set;get;}//設定/取得硬碟容量

}

class miniHardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來

int hd_gigabyte=0;//宣告一個變數來存取硬碟容量的值
public void setDefault()
{
hd_gigabyte = 40;

}
public bool compareHD(int HD)
{
if (HD > hd_gigabyte){return true;}
else{return false;}
}
public int HD_gigabyte
{
get { return hd_gigabyte; }
set {hd_gigabyte=value;}

}
}
class bigHardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來

int hd_gigabyte=0;//宣告一個變數來存取硬碟容量的值
public void setDefault()
{
hd_gigabyte = 1024;

}
public bool compareHD(int HD)
{
if (HD > hd_gigabyte) { return true; }
else { return false; }
}
public int HD_gigabyte
{
get { return hd_gigabyte; }
set { hd_gigabyte = value; }

}
}

class Computer
{
public IHardDisk Disk()
{
miniHardDisk cc = new miniHardDisk();
cc.setDefault();
return cc;
}
}


protected void Page_Load(object sender, EventArgs e)
{

IHardDisk Iabc = new Computer().Disk();
Response.Write("使用介面取得的值:");
Response.Write(Iabc.HD_gigabyte);
Response.Write("<br><br>");

Response.Write("使用bigHardDisk類別取得的值:");
bigHardDisk bHD = new bigHardDisk();
bHD.setDefault();
Response.Write(bHD.HD_gigabyte);
Response.Write("<br><br>");

Response.Write("使用miniHardDisk類別取得的值:");
miniHardDisk mHD = new miniHardDisk();
mHD.setDefault();
Response.Write(mHD.HD_gigabyte);



}

======================================
議題:
這時,也會有個疑問:
既然這樣的話,我還是一樣可以使用類別呀,
反正也是一定要創造兩個類別,那我在Page_Load時,再改呀
類別的寫法-->
Response.Write("使用bigHardDisk類別取得的值:");
miniHardDisk mHD = new miniHardDisk ();
mHD .setDefault();
Response.Write(mHD .HD_gigabyte);
Response.Write("<br><br>");
那當我要由小型硬碟改成大型時,就把
miniHardDisk mHD = new miniHardDisk ();
改成
bigHardDisk bHD = new bigHardDisk();
也行呀。
------------>
很好,說得沒錯,不過,首先,會先遇到個問題
「命名」,已由 mHD --> bHD ,勢必程式碼裡面的名稱都要修改
再者,假設,不修改名稱,我就硬用 mHD 用到底,反正都可以用嘛。
是啊,可以用,可是,又面臨到另個問題,
目前程式是只有一頁而已,那假設,我們已經使用原先物件的寫法,寫了10頁,
甚至於好幾十頁,請問,你要一支一支改嗎?
那如果我們使用「介面」的方法,就只要修改我們類別庫裡的該Computer類別即可。