1. 程式人生 > >C#介面和抽象類:Interface、abstract

C#介面和抽象類:Interface、abstract

一、介面

介面是C#中很常見的工具,概念什麼的就不說了,這裡講幾個值得注意的小地方:

1、介面內部只能有函式、屬性和事件的宣告:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->interface IParent
{
    
void
 Show();
    
string
 Type     //--屬性的宣告
    {
        
get
;           //-- get; 不能為get{};或是:get();

        
set;
    }
    
event
 AddChildren Add;
}

在介面中宣告的成員都不需要訪問修飾符(public,private等),因為介面成員的許可權預設都是public,另外值得注意的是介面中之所以能夠宣告事件是因為事件就是委託的特殊屬性。

介面不能是靜態的,介面成員也只能宣告為例項成員不能宣告為靜態成員,如下宣告就是錯誤的:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->static interface
 IParent
    {
        
staticvoid Show();
        
string Type
        {
            
get;
            
set;
        }
        
event AddChildren Add;
    }

你會得到提示:

錯誤 1 修飾符“static”對該項無效 C:\Documents and Settings\HMD\桌面\CLR_Excise\CLR_Excise\Lib.cs 10 22 CLR_Excise

原因是如果介面是靜態的就無法被繼承,靜態成員也無法被介面直接訪問(因為介面中的成員都還沒有實體只是宣告)所以定義在介面中無意義。

2、介面支援部分宣告:

上面的介面實際上可以在一個名稱空間裡宣告為3部分:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->partialinterface IParent
    {
        
void Show();
    }

    
partialinterface IParent
    {
        
string Type
        {
            
get;
            
set;
        }
    }

    
partialinterface IParent
    {
        
event AddChildren Add;
    }

上面這種部分介面的宣告方式和宣告為一個介面的效果完全相同,若要了解部分關鍵字partial請檢視:C#裡partial關鍵字的作用(轉摘)

3、介面的實現:

介面成員的實現方式分為兩種:

<1>隱式實現:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->class ChildrenA : IParent
        {

            
#region IParent 成員publicvoid Show()
            {
                
thrownew NotImplementedException();
            }


            
publicstring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
publicevent AddChildren Add;

            
#endregion
        }

 在類中隱式宣告的介面成員都必須是public訪問許可權

(2)如果有一個類C實現了兩個介面IA、IB且IA、IB都有同名函式void Display();那麼可以在C中隱式實現Display,這樣即實現了IA的Dislpay也實現了IB的Display

例如:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicinterface IParent
        {
            
void Show();
            
string Type
            {
                
get;
                
set;
            }
            
event AddChildren Add;
        }

        
publicinterface IFather
        {
            
void Show();
            
string Type
            {
                
get;
                
set;
            }
            
event AddChildren Add;
        }


        
publicclass ChildrenA : IParent, IFather
        {


            
#region IParent,IFather 成員publicvoid Show()
            {
                
thrownew NotImplementedException();
            }

            
publicstring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
publicevent AddChildren Add;

            
#endregion
        }

在上面類CA中將IParent和IFather的同名成員都用隱式實現介面成員的方式一次性實現了。

(3)隱式實現介面屬性的時候可以擴充介面屬性的訪問器,例如:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicinterface IParent
        {
            
string Type
            {
                
get;
            }
        }

        
publicclass CParent : IParent
        {

            
#region IParent 成員publicstring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }


            
#endregion
        }

本來介面屬性Type只有get訪問器,但是實現介面的類CParent擴充了介面屬性Type即定義了get訪問器也定義了set訪問器,這在隱式實現介面屬性的時候是允許的,但是在顯式實現介面屬性的時候必須嚴格按照介面定義的格式來!

<2>顯式宣告介面:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->class ChildrenA : IParent
        {

            
void IParent.Show()
            {
                
thrownew NotImplementedException();
            }


            
string IParent.Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
event AddChildren IParent.Add
            {
                add { 
thrownew NotImplementedException(); }
                remove { 
thrownew NotImplementedException(); }
            }
        }

顯式實現介面不能設定實現成員的訪問許可權(因為顯式宣告成員的許可權就是其對應介面成員的許可權,當然就是public)

此外顯式實現介面需要注意以下幾點:

(1)顯式實現介面,那麼實現的介面成員只能由介面呼叫,因為顯式實現的介面成員對於實現類來說是不可見的。

(2)顯式實現接事件的時候要注意,只能顯示實現事件的定義,例如顯式實現IParent.Add事件的時候,用的顯式實現事件:

event AddChildren IParent.Add
{
  add { throw new NotImplementedException(); }
  remove { throw new NotImplementedException(); }
}

如果用隱式實現事件就會報錯:

event AddChildren IParent.Add
提示:錯誤 1 事件的顯式介面實現必須使用事件訪問器語法 C:\Documents and Settings\HMD\桌面\CLR_Excise\CLR_Excise\Lib.cs 45 38 CLR_Excise

(3)上面隱式實現介面(3)中的例子沒有區分IParent、IFather同名成員的實現,而是在繼承類CA中由隱式實現方式統一實現。下面舉例說明如何將IParent、IFather的同名成員分別實現:

還是有一個類C實現了兩個介面IA、IB且IA、IB都有同名函式void Display();,這次為了區分IA,IB同名成員Dispaly函式的實現,可以在CA中將一個介面的Display函式用顯式方式實現,這說明在實現介面的時候可以將其中一個介面的同名成員用顯式方式實現,以區分同名成員的實現

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicdelegatevoid AddChildren();

        
interface IParent
        {
            
void Show();
            
string Type
            {
                
get;
                
set;
            }
            
event AddChildren Add;
        }

        
interface IFather
        {
            
void Show();
            
string Type
            {
                
get;
                
set;
            }
            
event AddChildren Add;
        }


        
class ChildrenA : IParent, IFather
        {


            
#region IParent 成員publicvoid Show()
            {
                
thrownew NotImplementedException();
            }

            
publicstring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
publicevent AddChildren Add;

            
#endregion#region IFather 成員void IFather.Show()
            {
                
thrownew NotImplementedException();
            }

            
string IFather.Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
event AddChildren IFather.Add
            {
                add { 
thrownew NotImplementedException(); }
                remove { 
thrownew NotImplementedException(); }
            }

            
#endregion
        }

現在就將IParent和IFather介面的同名成員分開實現了,其中將IFather介面的同名成員用顯式方式宣告以區分IParent介面的實現。事實上可以將IParent和IFather的成員都以顯式方式實現,不過這樣實現類CA就不能訪問到IParent和IFather的成員了,只有用IParent和IFather來訪問它們各自的成員。

 (4)如果實現類繼承了具有同名成員的抽象類,那麼加上override關鍵字後即實現了抽象類也實現了介面

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicdelegatevoid AddChildren();

        
interface IParent
        {
            
void Show();
            
string Type
            {
                
get;
                
set;
            }
            
event AddChildren Add;
        }

        
abstractclass AParent
        {
            
publicabstractvoid Show();
            
publicabstractstring Type
            {
                
get;
                
set;
            }
            
publicabstractevent AddChildren Add;
        }

        
class ChildrenA :AParent, IParent
        {


            
#region AParent、IParent 成員publicoverridevoid Show()
            {
                
thrownew NotImplementedException();
            }

            
publicoverridestring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
publicoverrideevent AddChildren Add;

            
#endregion

        }

二、抽象類

抽象類是C#裡面用的相對較少的工具,不過在有些場合他比介面更有用,抽象類的作用與介面類似就是宣告個框架,讓繼承類照著這個框架去實現,不過抽象類允許對已經確定的部分先進行實現,繼承類要做的就是實現沒有確定的成員(抽象成員)

abstract 修飾符可以和類、方法、屬性、索引器及事件一起使用。

在使用抽象類的時候需要注意:

(1)抽象類和介面一樣是個框架,本身不能被例項化,只能通過繼承類將其例項化。

(2)抽象類不能使用sealed和static關鍵字,因為使用sealed關鍵字表示類不能被繼承,而靜態類也不能被繼承,抽象類不被繼承是完全沒有意義的。

(3)實現抽象類的類必須實現抽象類的所有抽象成員(標記了abstract的成員):

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicabstractclass AParent
        {
            
publicabstractvoid Show();
            
publicabstractstring Type
            {
                
get;
                
set;
            }
            
publicabstractevent AddChildren Add;
            
public int tInt
            {
                get
                {
                    return 1;
                }
            }

        }

        
publicclass Parent : AParent
        {

            
publicoverridevoid Show()
            {
                
thrownew NotImplementedException();
            }

            
publicoverridestring Type
            {
                
get
                {
                    
thrownew NotImplementedException();
                }
                
set
                {
                    
thrownew NotImplementedException();
                }
            }

            
publicoverrideevent AddChildren Add;
        }

Parent類實現了AParent的所有抽象成員,但是並沒有實現AParent的非抽象成員public int tInt

(4)抽象成員都是虛成員(virtual),這一點上面的程式碼中可以看到,實現抽象類的成員都使用了關鍵字override(實現抽象成員必須要用override)表示重寫抽象類的抽象成員

(5)抽象成員不能標記為static(原因同介面)、virtual,且抽象成員不能是private的(原因就是private成員無法被繼承)。

(6)抽象類的抽象成員可以重寫(override)或隱藏(new)基類成員:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->abstractclass ACA
        {
            
publicabstractvoid Call();
        }

        
abstractclass ACB : ACA
        {
            
publicoverrideabstractvoid Call();
        }

如上所示ACB的抽象成員就重寫了父類ACA的抽象成員

(7)抽象類也支援部分定義,例如可以將(3)中的AParent分成3部分定義,其效果和定義成一個相同:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->publicabstractpartialclass AParent
        {
            
publicabstractvoid Show();
            
publicint tInt
            {
                
get
                {
                    
return1;
                }
            }
        }
        
publicabstractpartialclass AParent
        {
            
publicabstractstring Type
            {
                
get;
                
set;
            }
        }
        
publicabstractpartialclass AParent
        {
            
publicabstractevent AddChildren Add;
        }