كلاس ها ي abstract
كلاس ها را همچنين مي توان به صورت abstract تعريف كرد. از اين نوع كلاس ها نمي توان instance ايي را ايجاد نمود. در اين كلاس هاي پايه ، صرفا تعريف متدها و خواص هايي عنوان گرديده و در آينده در كلاس هاي فرزند توسعه داده خواهند شد. براي مثال :


public abstract class Named
{
public abstract String Name {get; set;} // property
public abstract void PrintName(); // method
}
public class B : Named
{
private String name = "empty";
public override String Name
{
get{return name;}
set{name=value;}
}
public override void PrintName()
{
Console.WriteLine("Name is {0}", name);
}
}


والي كه شايد پيش بيايد اين است كه اگر interface ها صرفا تعريف توابع و خواص را مي توانند در خود جاي دهند پس چه دليلي براي بكار بردن آنها و طولاني كردن كار كد نويسي وجود دارد؟
كاربردهاي زيادي را مي توان براي اينترفيس ها برشمرد. اينترفيس يك رفتار را تعريف مي كند. فرض كنيد در حال توسعه ي برنامه ايي هستيد كه بر روي دو كامپيوتر مختلف بايد با هم در ارتباط مستقيم بوده و برهم كنش داشته باشند و هر برنامه از ماژولي به نام CCommObj communication object استفاده مي نمايد. يكي از متدهاي اين شيء ، SendData() مي باشد كه رشته اي را دريافت كرده و به برنامه ي ديگر مي فرستد. اين فراخواني از نوع asynchronous است زيرا ما نمي خواهيم اگر خطايي در شبكه رخ داد، برنامه براي هميشه منتظر باقي بماند. اما چگونه برنامه ي A كه تابع ذكر شده را فراخواني كرده است مي تواند تشخيص دهد كه پيغام به مقصد رسيده است يا خير و يا آيا خطايي در شبكه مانع رسيدن پيغام گشته است يا خير؟ جواب بدين صورت است كه CCommObj هنگام دريافت پيغام ، رخدادي را سبب خواهد شد و اگر خطايي رخ داده باشد خير. در اين حالت نياز به يك ماژول logging نيز احساس مي گردد تا خطاهاي رخ داده را ثبت نمايد. يك روش انجام آن اين است كه CCommObj پياده سازي اين امكان را نيز بعهده گرفته و اگر فردا نيز خواستيم ماژول ديگري را به برنامه اضافه كنيم هر روز بايد CCommObj را تغيير دهيم. تمام اين كارها را به سادگي مي توان در يك اينترفيس مدل كرد. روش آن نيز در ادامه بيان مي گردد:
در ابتدا يك اينترفيس ايجاد مي كنيم تا ليست تمام امكانات ممكن را "منتشر" كند:


interface ICommObjEvents
{
void OnDataSent();
void OnError();
}


شي ء CCommObj ما از اين توابع كه بعدا توسعه داده خواهند شد براي با خبر سازي كلاينت ها استفاده مي نمايد. تمام متدها در يك اينترفيس ذاتا پابليك هستند بنابراين نيازي به ذكر صريح اين مطلب نمي باشد و اگر اينكار را انجام دهيد كامپايلر خطاي زير را گوشزد خواهد كرد :


The modifier 'public' is not valid for this item


در ادامه كلاينت CClientApp_A را پياده سازي خواهيم كرد :


class CClientApp_A:ICommObjEvents
{
public void OnDataSent()
{
Console.WriteLine("OnDataSent");
}
public void OnError()
{
Console.WriteLine("OnError");
}
private CCommObj m_Server;
public void Init(CCommObj theSource)
{
m_Server = theSource;
theSource.Advise (this);
string strAdd = ("N450:1");
m_Server.read (strAdd,10);
}
}


در كد فوق كلاس CClientApp_A از ICommObjEvents ارث برده و تمام متدهاي اين اينترفيس را پياده سازي نموده است. هنگامي كه CCommObj تابع OnDataSent را فراخواني مي كند اين كلاينت پيغام را دريافت خواهد كرد. لازم به ذكر است كه كلاس كلاينت ما چون از يك اينترفيس ارث بري مي نمايد پس بايد تمام توابع و خواص كلاس پايه را پياده سازي كند در غير اينصورت هر چند برنامه كامپايل خواهد شد اما هنگامي كه شيء CCommObj هر كدام از توابع اين كلاس را فراخواني كد ، خطاي زمان اجرا رخ خواهد داد.
متد Init كلاس فوق آرگوماني را از نوع CCommObj دريافت نموده و در يك متغير private آنرا ذخيره مي نمايد. همچنين در اين متد ، متد Advise از كلاس CCommObj نيز فراخواني گشته است.


public class CCommObj
{
private int m_nIndex;
public ICommObjEvents [] m_arSinkColl;
public CCommObj()
{
m_arSinkColl = new ICommObjEvents[10];
m_nIndex = 0;
}
public int Advise(ICommObjEvents theSink)
{
m_arSinkColl[m_nIndex] = theSink;
int lCookie = m_nIndex;
m_nIndex++;
return lCookie
}
public void SendData(string strData)
{
foreach ( ICommObjEvents theSink in m_arSinkColl)
if(theSink != null )
theSink.OnDataSent ();
}
}