C#基礎概念二十五問 16-20

來源:互聯網
上載者:User

16.類和結構的區別?

答:
類:

類是參考型別在堆上分配,類的執行個體進行賦值只是複製了引用,都指向同一段實際對象分配的記憶體

類有構造和解構函式

類可以繼承和被繼承

結構:

結構是實值型別在棧上分配(雖然棧的訪問速度比較堆要快,但棧的資源有限放),結構的賦值將分配產生一個新的對象。

結構沒有建構函式,但可以添加。結構沒有解構函式

結構不可以繼承自另一個結構或被繼承,但和類一樣可以繼承自介面

樣本:

根據以上比較,我們可以得出一些輕量級的對象最好使用結構,但資料量大或有複雜處理邏輯對象最好使用類。

如:Geoemtry(GIS 裡的一個概論,在 OGC 標準裡有定義) 最好使用類,而 Geometry 中點的成員最好使用結構

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

namespace Example16
{
interface IPoint
{
double X
{
get;
set;
}
double Y
{
get;
set;
}
double Z
{
get;
set;
}
}
//結構也可以從介面繼承
struct Point: IPoint
{
private double x, y, z;
//結構也可以增加建構函式
public Point(double X, double Y, double Z)
{
this.x = X;
this.y = Y;
this.z = Z;
}
public double X
{
get { return x; }
set { x = value; }
}
public double Y
{
get { return x; }
set { x = value; }
}
public double Z
{
get { return x; }
set { x = value; }
}
}
//在此簡化了點狀Geometry的設計,實際產品中還包含Project(座標變換)等複雜操作
class PointGeometry
{
private Point value;

public PointGeometry(double X, double Y, double Z)
{
value = new Point(X, Y, Z);
}
public PointGeometry(Point value)
{
//結構的賦值將分配新的記憶體
this.value = value;
}
public double X
{
get { return value.X; }
set { this.value.X = value; }
}
public double Y
{
get { return value.Y; }
set { this.value.Y = value; }
}
public double Z
{
get { return value.Z; }
set { this.value.Z = value; }
}
public static PointGeometry operator +(PointGeometry Left, PointGeometry Rigth)
{
return new PointGeometry(Left.X + Rigth.X, Left.Y + Rigth.Y, Left.Z + Rigth.Z);
}
public override string ToString()
{
return string.Format("X: {0}, Y: {1}, Z: {2}", value.X, value.Y, value.Z);
}
}
class Program
{
static void Main(string[] args)
{
Point tmpPoint = new Point(1, 2, 3);

PointGeometry tmpPG1 = new PointGeometry(tmpPoint);
PointGeometry tmpPG2 = new PointGeometry(tmpPoint);
tmpPG2.X = 4;
tmpPG2.Y = 5;
tmpPG2.Z = 6;

//由於結構是實值型別,tmpPG1 和 tmpPG2 的座標並不一樣
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG2);

//由於類是參考型別,對tmpPG1座標修改後影響到了tmpPG3
PointGeometry tmpPG3 = tmpPG1;
tmpPG1.X = 7;
tmpPG1.Y = 8;
tmpPG1.Z = 9;
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG3);

Console.ReadLine();
}
}
}
結果:
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
X: 7, Y: 8, Z: 9

17.介面的多繼承會帶來哪些問題?

答:

C# 中的介面與類不同,可以使用多繼承,即一個子介面可以有多個父介面。但如果兩個父成員具有同名的成員,就產生了二義性(這也正是 C# 中類取消了多繼承的原因之一),這時在實現時最好使用顯式的聲明

樣本:

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

namespace Example17
{
class Program
{
//一個完整的介面聲明樣本
interface IExample
{
//屬性
string P
{
get;
set;
}
//方法
string F(int Value);
//事件
event EventHandler E;
//索引指標
string this[int Index]
{
get;
set;
}
}
interface IA
{
int Count { get; set;}
}
interface IB
{
int Count();
}
//IC介面從IA和IB多重繼承
interface IC : IA, IB
{
}
class C : IC
{
private int count = 100;
//顯式聲明實現IA介面中的Count屬性
int IA.Count
{
get { return 100; }
set { count = value; }
}
//顯式聲明實現IB介面中的Count方法
int IB.Count()
{
return count * count;
}
}
static void Main(string[] args)
{
C tmpObj = new C();

//調用時也要顯式轉換
Console.WriteLine("Count property: {0}", ((IA)tmpObj).Count);
Console.WriteLine("Count function: {0}", ((IB)tmpObj).Count());

Console.ReadLine();
}
}
}
結果:
Count property: 100
Count function: 10000

18.抽象類別和介面的區別?

答:

抽象類別(abstract class)可以包含功能定義和實現,介面(interface)只能包含功能定義

抽象類別是從一系列相關對象中抽象出來的概念, 因此反映的是事物的內部共性;介面是為了滿足外部調用而定義的一個功能約定, 因此反映的是事物的外部特性

分析對象,提煉內部共性形成抽象類別,用以表示對象本質,即“是什麼”

為外部提供調用或功能需要擴充時優先使用介面

19.別名指示符是什嗎?

答:

通過別名指示符我們可以為某個類型起一個別名

主要用於解決兩個命名空間內有同名類型的衝突或避免使用冗餘的命名空間

別名指示符在所有命名空間最外層定義,範圍為整個單元檔案。如果定義在某個命名空間內,那麼它只在直接隸屬的命名空間內起作用

樣本:

Class1.cs:

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

namespace com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01
{
class Class1
{
public override string ToString()
{
return "com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01's Class1";
}
}
}
Class2.cs:

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

namespace com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02
{
class Class1
{
public override string ToString()
{
return "com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02's Class1";
}
}
}
主單元(Program.cs):

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

//使用別名指示符解決同名類型的衝突
//在所有命名空間最外層定義,範圍為整個單元檔案
using Lib01Class1 = com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;
using Lib02Class2 = com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02.Class1;

namespace Example19
{
namespace Test1
{
//Test1Class1在Test1命名空間內定義,範圍僅在Test1之內
using Test1Class1 = com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;

class Class1
{
//Lib01Class1和Lib02Class2在這可以正常使用
Lib01Class1 tmpObj1 = new Lib01Class1();
Lib02Class2 tmpObj2 = new Lib02Class2();
//TestClass1在這可以正常使用
Test1Class1 tmpObj3 = new Test1Class1();
}
}
namespace Test2
{
using Test1Class2 = com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;

class Program
{
static void Main(string[] args)
{
//Lib01Class1和Lib02Class2在這可以正常使用
Lib01Class1 tmpObj1 = new Lib01Class1();
Lib02Class2 tmpObj2 = new Lib02Class2();

//注意這裡,TestClass1在這不可以正常使用。
//因為,在Test2命名空間內不能使用Test1命名空間定義的別名
//Test1Class1 tmpObj3 = new Test1Class1();

//TestClass2在這可以正常使用
Test1Class2 tmpObj3 = new Test1Class2();

Console.WriteLine(tmpObj1);
Console.WriteLine(tmpObj2);
Console.WriteLine(tmpObj3);

Console.ReadLine();
}
}
}
}

結果:
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01's Class1
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02's Class1
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01's Class1

20.如何手工釋放資源?

答:

.NET 平台在記憶體管理方面提供了GC(Garbage Collection),負責自動釋放託管資源和記憶體回收的工作。但在以下兩種情況需要我們手工進行資源釋放:一、由於它無法對非託管資源進行釋放,所以我們必須自己提供方法來釋放對象內分配的非託管資源,比如你在對象的實現代碼中使用了一個COM對象;二、你的類在運行是會產生大量執行個體(象 GIS 中的Geometry),必須自己手工釋放這些資源以提高程式的運行效率

最理想的辦法是通過實現一個介面顯式的提供給客戶調用端手工釋放對象,System 命名空間內有一個 IDisposable 介面,拿來做這事非常合適,省得我們自己再聲明一個介面了
樣本:

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

namespace Example20
{
class Program
{
class Class1 : IDisposable
{
//解構函式,編譯後變成 protected void Finalize(),GC會在回收對象前會調用調用該方法
~Class1()
{
Dispose(false);
}

//通過實現該介面,客戶可以顯式地釋放對象,而不需要等待GC來釋放資源,據說那樣會降低效率
void IDisposable.Dispose()
{
Dispose(true);
}

//將釋放非託管資源設計成一個虛函數,提供在繼承類中釋放基類的資源的能力
protected virtual void ReleaseUnmanageResources()
{
//Do something...
}

//私人函數用以釋放非託管資源
private void Dispose(bool disposing)
{
ReleaseUnmanageResources();

//為true時表示是客戶顯式調用了釋放函數,需通知GC不要再調用對象的Finalize方法
//為false時肯定是GC調用了對象的Finalize方法,所以沒有必要再告訴GC你不要調用我的Finalize方法啦
if (disposing)
{
GC.SuppressFinalize(this);
}
}
}
static void Main(string[] args)
{
//tmpObj1沒有手工釋放資源,就等著GC來慢慢的釋放它吧
Class1 tmpObj1 = new Class1();

//tmpObj2調用了Dispose方法,傳說比等著GC來釋放它效率要調一些
//個人認為是因為要逐個對象的查看其中繼資料,以確認是否實現了Dispose方法吧
//當然最重要的是我們可以自己確定釋放的時間以節省記憶體,最佳化程式運行效率
Class1 tmpObj2 = new Class1();
((IDisposable)tmpObj2).Dispose();
}
}
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.