9. Indekser dan Properti
Bab ini akan
membahas dua tipe anggota kelas yang satu sama lain memiliki relasi yang sangat
dekat: indekser dan properti. Masing-masing mempunyai kontribusi dalam
mengintegrasikan dan meningkatkan kehandalan sistem tipe C#. Indekser merupakan
suatu mekanisme sehingga sebuah objek dapat diindeks seperti array. Properti
berperan untuk mengelola akses terhadap data instans suatu kelas. Keduanya
berelasi satu sama lain karena bergantung pada fitur C# yang lain: aksesor.
Indekser
Indekser membuat
sebuah objek diindeks seperti layaknya array. Kegunaan utama indekser adalah
untuk mendukung penciptaan array terspesialisasi, yang memiliki satu atau dua kekangan.
Indekser dapat mempunyai satu atau lebih dimensi. Pembahasan akan dimulai
dengan indekser satu dimensi.
Menciptakan
Indekser Satu Dimensi
Indekser satu
dimensi mempunyai bentuk umum sebagai berikut:
tipe-elemen this[int indeks] {
// Aksesor get
get {
// menjadikan nilai yang dispesifikasi oleh
indeks sebagai nilai balik
}
// Aksesor set
set {
// menetapkan nilai yang dispesifikasi oleh
indeks
}
}
Di sini, tipe-elemen merupakan tipe
elemen dari indekser. Jadi, setiap elemen yang diakses oleh indekser bertipe tipe-elemen. Tipe ini
berkaitan dengan tipe elemen suatu array. Parameter indeks menerima indeks
elemen yang sedang diakses. Secara teknis, parameter ini tidak harus bertipe int, tetapi karena indeks secara umum
dipakai untuk pengindeksan array, penggunaan tipe integer paling umum
digunakan.
Di dalam tubuh
indekser, terdapat dua aksesor yang didefinisikan, dinamakan dengan get dan set. Aksesor sama dengan sebuah metode kecuali bahwa ia tidak
mendeklarasikan tipe nilai balik atau parameter. Aksesor ini secara otomatis
dipanggil ketika indekser dipakai, dan kedua aksesor menerima indeks sebagai
parameter. Jika indekser berada di sisi kiri suatu statemen penugasan, maka
aksesor set dipanggil dan elemen
yang dispesifikasi oleh indeks harus ditetapkan. Sebaliknya, aksesor get dipanggil dan nilai yang berkaitan dengan indeks dijadikan nilai
balik. Metode set juga menerima
sebuah parameter implisit, dinamakan value,
yang memuat nilai yang sedang ditugaskan kepada indeks yang dispesifikasi.
Salah satu
keuntungan dari indekser adalah bahwa Anda dapat mengendalikan bagaimana array
diakses. Berikut disajikan sebuah contoh. Pada program berikut, Kelas ArrayGagalHalus mengimple-mentasikan
sebuah array yang mengakses di luar batas indeksnya. Ini dilakukan dengan
mengenkapsulasi array tersebut sebagai anggota privat kelas, sehingga
pengaksesan array hanya bisa dilakukan melalui indekser. Dengan pendekatan ini,
semua percobaan untuk mengakses array di luar batasnya akan dicegah. Karena ArrayGagalHalus menggunakan indekser,
array dapat diakses menggunakan notasi array biasa.
// Menggunakan indekser untuk menciptakan array gagal-halus.
using System;
class ArrayGagalHalus {
int[] a; // referensi ke array
public int Panjang; // Panjang dideklarasikan public
public bool ErrFlag; // mengindikasikan keluaran operasi terakhir
// Mengkonstruksi
array dengan ukuran tertentu.
public ArrayGagalHalus(int ukuran) {
a = new int[ukuran];
Panjang = ukuran;
}
// Ini adalah
indekser untuk ArrayGagalHalus.
public int this[int
indeks] {
// Ini adalah
aksesor get.
get {
if (ok(indeks))
{
ErrFlag = false;
return a[indeks];
} else {
ErrFlag = true;
return 0;
}
}
// Ini adalah aksesor
set.
set
{
if (ok(indeks))
{
a[indeks] =
value;
ErrFlag = false;
}
else ErrFlag = true;
}
}
// Menghasilkan true
jika indeks di dalam batas.
private bool ok(int
indeks)
{
if (indeks >= 0 & indeks <
Panjang) return true;
return false;
}
}
// Mendemonstrasikan array gagal-halus.
class DemoGH {
static void Main(){
ArrayGagalHalus fs
= new ArrayGagalHalus(5);
int x;
// Menampilkan
gagal halus.
Console.WriteLine("Gagal secara halus.");
for (int i = 0; i < (fs.Panjang * 2); i++)
fs[i] = i * 10;
for (int i = 0; i < (fs.Panjang * 2); i++)
{
x = fs[i];
if (x != -1) Console.Write(x + " ");
}
Console.WriteLine();
// Sekarang,
menampilkan kegagalan.
Console.WriteLine("\nGagal dengan laporan error.");
for (int i = 0; i < (fs.Panjang *
2); i++)
{
fs[i] = i * 10;
if (fs.ErrFlag)
Console.WriteLine("fs[" + i +
"] di luar batas array");
}
for (int i = 0; i < (fs.Panjang * 2); i++)
{
x = fs[i];
if (!fs.ErrFlag) Console.Write(x + " ");
else
Console.WriteLine("fs[" + i +
"] di luar batas array");
}
}
}
Keluaran program
ditampilkan di sini:
Gagal secara halus.
0 10 20 30 40 0 0 0 0 0
Gagal dengan laporan error.
fs[5] di luar batas array
fs[6] di luar batas array
fs[7] di luar batas array
fs[8] di luar batas array
fs[9] di luar batas array
0 10 20 30 40 fs[5] di luar batas array
fs[6] di luar batas array
fs[7] di luar batas array
fs[8] di luar batas array
fs[9] di luar batas array
Indekser
mencegah pengaksesan di luar batas array. Akan ditengok lebih dekat pada setiap
bagian indekser. Dimulai dengan baris ini:
public int this[int indeks] {
Ini
mendeklarasikan sebuah indeks yang beroperasi pada elemen int. Indeks ini dilewatkan di dalam indeks. Indekser dideklarasikan publik, sehingga dapat digunakan
oleh sembarang kode di luar kelasnya.
Aksesor get ditampilkan di sini:
// Ini adalah indekser untuk ArrayGagalHalus.
public
int this[int indeks] {
// Ini adalah aksesor get.
get
{
if
(ok(indeks))
{
ErrFlag = false;
return
a[indeks];
} else
{
ErrFlag = true;
return
0;
}
}
Aksesor get mencegah error batas array dengan
pertama-tama memastikan bahwa indeks tidak di luar batas array. Pemeriksaan
rentang ini dilakukan oleh metode ok(),
yang menghasilkan nilai balik true
jika indeks valid dan false jika
sebaliknya. Jika indeks yang dispesifikasi berada di dalam retang yang
diijinkan, elemen terkait dengan indeks tersebut akan dijadikan nilai balik.
Jika ia berada di luar batas, tidak ada operasi apapun yang dilakukan dan
pengaksesan array di luar batas tidak terjadi. Pada versi ArrayGagalHalus ini, sebuah variabel, dinamakan ErrFlag, memuat keluaran setiap
operasi. Bidang ini diuji pada tiap operasi untuk menentukan kegagalan atau
keberhasilan operasi. (Pada Bab 12, Anda akan melihat cara lebih baik dalam
menangani error dengan menggunakan penanganan eksepsi C#).
Aksesor set ditampilkan di sini. Aksesor ini
juga mencegah error di-luar-batas:
// Ini adalah aksesor set.
set
{
if
(ok(indeks))
{
a[indeks] = value;
ErrFlag = false;
}
else
ErrFlag = true;
}
}
Di sini, jika indeks di dalam rentang yang diijinkan,
nilai yang dilewatkan di dalam value
ditugaskan kepada elemen terkait. Sebaliknya, ErrFlag akan ditetapkan true.
Ingat bahwa di dalam sebuah metode aksesor, value merupakan parameter implisit yang memuat nilai yang sedang
ditugaskan. Anda tidak perlu mendeklarasikannya.
Sebuah indekser
tidak perlu mendukung kedua get dan set. Anda dapat menciptakan indekser read-only
dengan hanya mengimplamentasikan aksesor get.
Anda dapat menciptakan indekser write-only dengan hanya mengimplementasikan
aksesor set.
Indekser
Dapat Dioverload
Sebuah indekser
dapat dioverload. Berikut adalah sebuah contoh yang mengoverload indekser ArrayGagalHalus untuk indeks bertipe double. Indekser double membulatkan indeksenya menjadi nilai integer terdekat.
// Mengoverload indekser ArrayGagalHalus.
using System;
class ArrayGagalHalus {
int[] a; // referensi ke array
public int Panjang; // Panjang dideklarasikan public
public bool ErrFlag; // mengindikasikan keluaran operasi terakhir
// Mengkonstruksi
array dengan ukuran tertentu.
public ArrayGagalHalus(int
ukuran) {
a = new int[ukuran];
Panjang = ukuran;
}
// Ini adalah
indekser untuk ArrayGagalHalus.
public int this[int
indeks] {
// Ini adalah
aksesor get.
get {
if (ok(indeks))
{
ErrFlag = false;
return a[indeks];
} else {
ErrFlag = true;
return 0;
}
}
// Ini adalah aksesor
set.
set
{
if (ok(indeks))
{
a[indeks] = value;
ErrFlag = false;
}
else ErrFlag = true;
}
}
/* Ini adalah
indekser lain untuk ArrayGagalHalus.
Indeks ini
mengambil argumen double. Indeks tersebut
membulatkan
argumen menjadi indeks integer terdekat. */
public int this[double idx]
{
// Ini adalah
aksesor get.
get
{
int indeks;
// Membulatkan ke
int terdekat.
if ((idx - (int)idx) < 0.5) indeks = (int)idx;
else indeks = (int)idx + 1;
if (ok(indeks))
{
ErrFlag = false;
return a[indeks];
}
else
{
ErrFlag = true;
return 0;
}
}
// Ini adalah
aksesor set.
set
{
int indeks;
// Membulatkan ke
int terdekat.
if ((idx - (int)idx) < 0.5) indeks = (int)idx;
else indeks = (int)idx + 1;
if (ok(indeks))
{
a[indeks] = value;
ErrFlag = false;
}
else ErrFlag = true;
}
}
// Menghasilkan true
jika indeks di dalam batas.
private bool ok(int
indeks)
{
if (indeks >= 0 & indeks <
Panjang) return true;
return false;
}
}
// Mendemonstrasikan array gagal-halus.
class DemoGH {
static void Main(){
ArrayGagalHalus fs
= new ArrayGagalHalus(5);
// Menempatkan
beberapa nilai di dalam fs.
for(int i=0; i < fs.Panjang; i++)
fs[i] = i;
// Sekarang indeks
dengan int dan double.
Console.WriteLine("fs[1]: " + fs[1]);
Console.WriteLine("fs[2]: " + fs[2]);
Console.WriteLine("fs[1.1]: " + fs[1.1]);
Console.WriteLine("fs[1.6]: " + fs[1.6]);
}
}
Program ini
menghasilkan keluaran sebagai berikut:
fs[1]: 1
fs[2]: 2
fs[1.1]: 1
fs[1.6]: 2
Seperti
ditampilkan keluaran, indeks double
dibulatkan ke nilai integer terdekat. Dapat diperhatikan bahwa 1.1 dibulatkan
ke 1, dan 1.6 dibulatkan ke 2.
Indekser
Tidak Harus Memerlukan Array
Penting untuk
dipahami bahwa tidak ada keharusan bagi indekser untuk beroperasi pada sebuah
array. Indekser hanya harus mempunyai fungsionalitas “seperti-array”. Sebagai
contoh, program berikut mempunyai indekser yang berperan sebagai array read-only
yang memuat 2 pangkat 0 sampai 2 pangkat 15. Perhatikan bahwa tidak ada array
aktual. Indekser hanya menghitung nilai yang diinginkan untuk indeks tertentu.
// Indekser tidak harus
beroperasi pada array aktual.
using System;
class DuaPangkat
{
/* Mengakses array logikal yang memuat
2 pangkat 0 sampai 15. */
public
int this[int indeks]
{
// Menghitung dan menghasilkan 2
pangkat sekian.
get
{
if ((indeks >= 0) && (indeks < 16)) return pangkat(indeks);
else return -1;
}
// Tidak ada aksesor set.
}
int
pangkat(int p)
{
int
hasil = 1;
for
(int i = 0; i < p; i++)
hasil *= 2;
return
hasil;
}
}
class GunakanPangkatDua {
static
void Main() {
DuaPangkat pangkat = new DuaPangkat();
Console.Write("2 pangkat 0 sampai 2 pangkat 8:
");
for
(int i = 0; i < 8; i++)
Console.Write(pangkat[i] + " ");
Console.WriteLine();
Console.Write("Berikut adalah beberapa error: ");
Console.Write(pangkat[-1]
+ " " + pangkat[17]);
Console.WriteLine();
}
}
Keluaran program
ditunjukkan di sini:
2 pangkat 0 sampai 2 pangkat 8: 1 2 4 8 16 32 64 128
Berikut adalah beberapa error: -1 -1
Perhatikan bahwa
indekser untuk DuaPangkat
mencantumkan sebuah aksesor get,
tetapi tidak memiliki aksesor set.
Seperti yang telah dijelaskan sebelumnya, ini merupakan indekser read-only.
Jadi, sebuah objek DuaPangkat dapat
dipakai di sisi kanan penugasan, tetapi tidak di sisi kiri. Sebagai contoh,
jika Anda mencoba menambahkan statemen ini pada program, maka program tidak
akan bisa dikompilasi:
pangkat[0] = 11; // tidak akan bisa dikompilasi
Statemen ini
akan menyebabkan error kompilasi karena tidak ada aksesor set yang didefinisikan untuk indekser.
Ada dua batasan
penting dalam menggunakan indekser. Pertama, karena indekser tidak
mendefinisikan lokasi penyimpanan, nilai yang dihasilkan oleh indekser tidak
bisa dilewatkan sebagai parameter ref
atau out kepada sebuah metode.
Kedua, indekser harus merupakan anggota instans dari kelasnya; ia tidak bisa
dideklarasikan static.
Indekser
Multidimensi
Anda dapat
menciptakan indekser untuk array multidimensi. Sebagai contoh, berikut adalah
sebuah array multidimensi gagal-halus. Perhatikan secara dekat cara indekser
dideklarasikan.
// Sebuah array multidimensi gagal-halus.
using System;
class Array2DGagalHalus {
int[,] a; // referensi ke array 2D
int baris, kolom; // dimensi
public int Panjang; // Panjang dideklarasikan public
public bool ErrFlag; // mengindikasikan keluaran operasi terakhir
// Mengkonstruksi
array dari dimensi yang diberikan.
public Array2DGagalHalus(int
r, int c) {
baris = r;
kolom = c;
a = new int[baris, kolom];
Panjang = baris *
kolom;
}
// Ini adalah
indekser untuk Array2DGagalHalus.
public int this[int
indeks1, int indeks2] {
// Ini adalah
aksesor get.
get {
if(ok(indeks1, indeks2)) {
ErrFlag = false;
return a[indeks1, indeks2];
} else {
ErrFlag = true;
return 0;
}
}
// Ini adalah
aksesor set.
set {
if(ok(indeks1, indeks2)) {
a[indeks1,
indeks2] = value;
ErrFlag = false;
}
else ErrFlag = true;
}
}
// Menghasilkan true
jika indeks di dalam batas.
private bool ok(int
indeks1, int indeks2) {
if(indeks1 >= 0
& indeks1 < baris &
indeks2 >= 0
& indeks2 < kolom)
return true;
return false;
}
}
// Demonstrasi indekser 2D.
class DemoDuaDIndekser {
static void Main() {
Array2DGagalHalus
fs = new Array2DGagalHalus(3, 5);
int x;
// Menampilkan
kegagalan diam.
Console.WriteLine("Gagal secara diam-diam.");
for(int i=0; i < 6; i++)
fs[i, i] = i*10;
for(int i=0; i < 6; i++) {
x = fs[i,i];
if(x != -1) Console.Write(x + " ");
}
Console.WriteLine();
// Sekarang,
tampilkan kegagalan.
Console.WriteLine("\nKegagalan dengan laporan error.");
for (int i = 0; i < 6; i++)
{
fs[i, i] = i *
10;
if (fs.ErrFlag)
Console.WriteLine("fs[" + i +
", " + i + "] di luar batas
error");
}
for (int i = 0; i < 6; i++)
{
x = fs[i, i];
if (!fs.ErrFlag) Console.Write(x + " ");
else
Console.WriteLine("fs[" + i + ", " + i + "] di luar batas error");
}
}
}
Keluaran program
yang dihasilkan ditampilkan di sini:
Gagal secara diam-diam.
0 10 20 0 0 0
Kegagalan dengan laporan error.
fs[3, 3] di luar batas error
fs[4, 4] di luar batas error
fs[5, 5] di luar batas error
0 10 20 fs[3, 3] di luar batas error
fs[4, 4] di luar batas error
fs[5, 5] di luar batas error
Properti
Tipe lain dari
anggota kelas adalah properti. Aturan umumnya adalah bahwa sebuah properti
menggabungkan bidang dengan metode yang mengaksesnya. Anda mungkin seringkali
ingin menciptakan sebuah bidang yang tersedia bagi pengguna sebuah objek,
tetapi Anda juga ingin mengendalikan operasi apa saja yang boleh diterapkan
pada bidang tersebut. Misalnya, Anda ingin membatasi rentang nilai yang dapat
ditugaskan kepada bidang tersebut. Meskipun dimungkinkan untuk melakukan tujuan
ini dengan memanfaatkan variabel privat dengan metode yang bisa mengaksesnya,
properti menawarkan pendekatan yang lebih baik.
Properti sama
dengan indekser. Properti memuat sebuah nama dengan aksesor get dan set. Aksesor tersebut dipakai untuk mendapatkan dan menetapkan
nilai sebuah variabel. Keuntungan kunci dari properti adalah bahwa namanya
dapat dipakai di dalam ekspresi dan penugasan seperti halnya variabel
biasa. Pada kasus tersebut, aksesor get dan set dipanggil secara otomatis.
Bentuk umum dari
sebuah properti ditunjukkan di sini:
tipe nama {
get {
// kode aksesor get
}
set {
// kode aksesor set
}
}
Di sini, tipe menspesifikasi
tipe properti, seperti int, dan nama adalah nama
dari properti. Begitu properti didefinisikan, sembarang penggunaan dari nama akan
menghasilkan pemanggilan terhadap aksesornya. Aksesor set secara otomatis menerima parameter, yang dinamakan value, yang memuat nilai yang sedang
ditugaskan kepada properti.
Penting untuk
memahami bahwa properti tidak mendefinisikan lokasi penyimpanan. Properti
secara umum mengelola akses ke suatu bidang. Ia sendiri tidak menyediakan
bidang tersebut. Bidang harus dispesifikasi secara independen dari properti.
Berikut adalah sebuah
contoh yang mendemonstrasikan sebuah properti, yang dinamakan PropKu, yang digunakan untuk mengakses
bidang prop. Pada kasus ini,
properti hanya membolehkan penugasan nilai positif.
// Contoh sederhana
properti.
using System;
class PropSederhana
{
int
prop; // bidang yang dikelola oleh PropKu
public
PropSederhana() { prop = 0; }
/* Ini adalah properti yang mendukung akses
terhadap
variabel instans private prop. Ia hanya
membolehkan
penugasan nilai positif. */
public
int PropKu
{
get
{
return prop;
}
set
{
if (value >= 0) prop = value;
}
}
}
// Demonstrasi sebuah
properti.
class DemoProperti
{
static
void Main()
{
PropSederhana ob = new PropSederhana();
Console.WriteLine("Nilai asli dari ob.PropKu: " +
ob.PropKu);
ob.PropKu = 100; // menugaskan nilai
Console.WriteLine("Nilai dari ob.PropKu: " +
ob.PropKu);
// Tidak bisa menugaskan nilai negatif
kepada prop.
Console.WriteLine("Mencoba menugaskan -10 kepada ob.PropKu");
ob.PropKu = -10;
Console.WriteLine("Nilai dari ob.PropKu: " +
ob.PropKu);
}
}
Keluaran program
ditampilkan di sini:
Nilai asli dari ob.PropKu: 0
Nilai dari ob.PropKu: 100
Mencoba menugaskan -10 kepada ob.PropKu
Nilai dari ob.PropKu: 100
Akan dibahas
program ini dengan hati-hati. Program mendefinisikan satu bidang privat, yang
dinamakan prop, dan sebuah properti,
yang dinamakan PropKu, yang
mengelola akses terhadap prop.
Seperti dijelaskan sebelumnya, properti sendiri tidak mendefinisikan lokasi
penyimpanan, properti hanya mengelola akses terhadap sebuah bidang. Di samping
itu, karena prop dideklarasikan private, ia hanya bisa diakses melalui PropKu.
Properti PropKu dispesifikasi sebagai public sehingga ia dapat diakses oleh
kode di luar kelasnya. Ini masuk akal karena ia menyediakan akses terhadap prop, yang dideklarasikan private. Aksesor get hanya menjadikan nilai prop
sebagai nilai balik. Aksesor set
menetapkan nilai prop jika dan hanya
jika nilai tersebut positif. Jadi, properti PropKu mengendalikan nilai yang bisa ditugaskan kepada prop. Ini merupakan esensi dari
properti.
TIpe properti
yang didefinisikan oleh PropKu
disebut dengan poperti read-write karena ia mengijinkan bidang untuk dibaca dan
ditulis. Untuk menciptakan properti read-only, Anda hanya perlu mendefinisikan
aksesor get. Untuk menciptakan
properti write-only, Anda hanya perlu mendefinisikan aksesor set.
Anda dapat
menggunakan sebuah properti untuk memperbaiki array kelas gagal-halus. Seperti
Anda ketahui, semua array mempunyai properti Length. Sampai saat ini, kelas ArrayGagalHalus
hanya menggunakan sebuah bidang integer publik, yang dinamakan Panjang untuk tujuan ini. Hal itu tidak
direkomendasikan, karena bisa saja Panjang
ditetapkan tidak sama dengan panjang array terkait. Situasi ini akan diperbaiki
dengan memanfaatkan Length, sebuah bidang read-only, seperti ditunjukkan pada
versi ArrayGagalHalus berikut:
// Menambahkan properti Length pada ArrayGagalHalus.
using System;
class ArrayGagalHalus
{
int[] a; // referensi ke array
int Panjang; // Panjang array
public bool ErrFlag; // mengindikasikan
keluaran operasi terakhir
// Mengkonstruksi
array dengan ukuran tertentu.
public ArrayGagalHalus(int ukuran)
{
a = new int[ukuran];
Panjang =
ukuran;
}
// Properti Length
read-only.
public int Length
{
get
{
return Panjang;
}
}
// Ini adalah
indekser untuk ArrayGagalHalus.
public int this[int indeks]
{
// Ini adalah
aksesor get.
get
{
if (ok(indeks))
{
ErrFlag
= false;
return a[indeks];
}
else
{
ErrFlag
= true;
return 0;
}
}
// Ini adalah
aksesor set.
set
{
if (ok(indeks))
{
a[indeks] = value;
ErrFlag
= false;
}
else ErrFlag = true;
}
}
// Menghasilkan
true jika indeks di dalam batas.
private bool ok(int indeks)
{
if (indeks >= 0 & indeks <
Length) return true;
return false;
}
}
// Mendemonstrasikan array gagal-halus terperbaiki
class DemoGHTerperbaiki
{
static void Main()
{
ArrayGagalHalus
fs = new ArrayGagalHalus(5);
int x;
// Dapat
membaca Length.
for (int i = 0; i < fs.Length; i++)
fs[i] = i *
10;
for (int i = 0; i < fs.Length; i++)
{
x = fs[i];
if (x != -1) Console.Write(x + " ");
}
Console.WriteLine();
// fs.Length =
10; // Error, ilegal!
}
}
Length sekarang adalah properti yang menggunakan variabel private, Panjang, untuk penyimpanannya. Length
hanya mendefinisikan aksesor get, yang berarti ia adalah properti read-only.
Jadi, Length hanya bisa dibaca, dan
tidak bisa diubah. Untuk membuktikannya, Anda bisa menghapus simbol komentar
yang ada di awal baris ini:
// fs.Length = 10; // Error, ilegal!
Ketika Anda
mencoba mengkompilasinya, Anda akan menerima pesan error yang menyatakan bahwa Length adalah read-only. Meskipun
penambahan properti Length
memperbaiki ArrayGagalHalus, itu
bukan satu-satunya perbaikan yang bisa dilakukan menggunakan properti. Anggota ErrFlag juga merupakan kandidat utama
yang bisa diubah menjadi properti karena akses terhadapnya harus dibatasi hanya
bersifat read-only. Berikut adalah perbaikan akhir atas ArrayGagalHalus, yang menciptakan sebuah properti, bernama Error, yang menggunakan variabel asli ErrFlag sebagai penyimpananya.
// Menambahkan properti Error pada ArrayGagalHalus.
using System;
class ArrayGagalHalus
{
int[] a; // referensi ke array
int Panjang; // Panjang array
public bool ErrFlag; // mengindikasikan
keluaran operasi terakhir
// Mengkonstruksi
array dengan ukuran tertentu.
public ArrayGagalHalus(int ukuran)
{
a = new int[ukuran];
Panjang =
ukuran;
}
// Properti Length
read-only.
public int Length
{
get
{
return Panjang;
}
}
// Properti Error
read-only.
public bool Error
{
get
{
return ErrFlag;
}
}
// Ini adalah
indekser untuk ArrayGagalHalus.
public int this[int indeks]
{
// Ini adalah
aksesor get.
get
{
if (ok(indeks))
{
ErrFlag
= false;
return a[indeks];
}
else
{
ErrFlag
= true;
return 0;
}
}
// Ini adalah
aksesor set.
set
{
if (ok(indeks))
{
a[indeks] = value;
ErrFlag
= false;
}
else ErrFlag = true;
}
}
// Menghasilkan
true jika indeks di dalam batas.
private bool ok(int indeks)
{
if (indeks
>= 0 & indeks < Length) return
true;
return false;
}
}
// Mendemonstrasikan array gagal-halus terperbaiki
class DemoGHAkhir
{
static void Main()
{
ArrayGagalHalus
fs = new ArrayGagalHalus(5);
// Menggunakan
properti Error.
for (int i = 0; i < fs.Length + 1; i++)
{
fs[i] = i *
10;
if (fs.Error)
Console.WriteLine("Error dengan indeks " + i);
}
}
}
Menggunakan
Penginisialisasi Objek Dengan Properti
Seperti
didiskusikan pada Bab 7, penginisialisasi objek menyediakan cara alternatif
dalam memanggil secara eksplisit sebuah konstruktor ketika penciptaan objek
dilakukan. Ketika menggunakan penginisialisasi objek, Anda harus menspesifikasi
nilai awal untuk bidang dan/atau properti yang ingin diinisialisasi. Di samping
itu, sintaks penginisialisasi objek sama untuk bidang maupun properti. Sebagai
contoh, di sini didemonstrasikan penginisialisasi objek dari Bab 7, dikerjakan
ulang untuk menunjukkan kegunaan penginisialisasi objek dengan properti. Ingat
bahwa versi pada Bab 7 menggunakan bidang. Satu-satunya perbedaan antara versi
ini dengan yang ada pada Bab 7 adalah bahwa Hitung dan Str
dikonversi dari bidang menjadi properti. Sintaks penginisialisasi objek tidak
berubah.
// Menggunakan
penginisialisasi objek dengan properti.
using System;
class KelasKu
{
// Sekarang ini properti.
public
int Hitung { get; set; }
public
string Str { get; set; }
}
class DemoInitObjek
{
static
void Main()
{
// Menciptakan sebuah objek KelasKu
menggunakan penginisialisasi objek.
KelasKu obj = new KelasKu { Hitung = 100, Str = "Pengujian" };
Console.WriteLine(obj.Hitung
+ " " + obj.Str);
}
}
Seperti yang
dapat Anda lihat, properti Hitung
dan Str ditetapkan melalui ekspresi
penginisialisasi objek. Keluarannya sama dengan yang dihasilkan pada Bab 7 dan
ditampilkan kembali di sini:
110 Pengujian
Menggunakan
Pemodifikasi Akses Dengan Aksesor
Secara default,
aksesor set dan get memiliki aksesibilitas sebagai indekser atau properti. Sebagai
contoh, jika properti dideklarasikan public,
maka secara default aksesor set dan get juga public. Dimungkinkan untuk memberikan pemodifikasi akses private bagi set dan get.
Ada sejumlah
alasan mengapa Anda ingin membatasi aksesibilitas suatu aksesor. Sebagai
contoh, Anda mungkin ingin membiarkan semua orang bisa memperoleh nilai sebuah
properti, tetapi hanya mengijinkan anggota kelasnya saja untuk menetapkan nilai
properti. Untuk melakukannya, aksesor set
dideklarasikan sebagai private.
Sebagai contoh, berikut adalah sebuah properti, bernama PropKu, yang mempunyai aksesor set
dispesifikasi sebagai private.
// Menggunakan pemodifikasi
akses dengan aksesor.
using System;
class AksesProp {
int
prop; // bidang yang sedang dikelola oleh PropKu
public
AksesProp() { prop = 0; }
/* Ini adalah properti yang mendukung akses
terhadap
variabel instans private prop. Properti
ini mengijinkan
sembarang kode untuk mendapatkan nilai
prop, tetapi hanya
anggota kelasnya yang bisa menetapkan
nilai prop. */
public
int PropKu {
get
{
return
prop;
}
private
set { // sekarang, private
prop = value;
}
}
// Anggota kelas ini menginkremen nilai dari
PropKu.
public
void InkrProp()
{
PropKu++; // OK, dalam sesama kelas.
}
}
// Demonstrasi pemodifikasi
akses aksesor.
class DemoAksesProp
{
static void Main()
{
AksesProp ob = new AksesProp();
Console.WriteLine("Nilai asli dari ob.PropKu: " +
ob.PropKu);
// ob.PropKu = 100; // tidak dapat
mengakses set
ob.InkrProp();
Console.WriteLine("Nilai dari ob.PropKu setelah inkremen:
"
+ ob.PropKu);
}
}
Keluaran program
ditampilkan di sini:
Nilai asli dari ob.PropKu: 0
Nilai dari ob.PropKu setelah inkremen: 1
Pada kelas AksesPro, aksesor set dispesifikasi private.
Ini berarti bahwa ia dapat diakses hanya oleh anggota kelas, seperti InkrProp(), tetapi tidak bisa diakses
oleh kode di luar AksesPro. Inilah
mengapa percobaan untuk menugaskan sebuah nilai kepada ob.PropKu di dalam DemoAksesProp
tidak bisa dilakukan.
Berikut
disajikan satu lagi contoh, dimana aksesor set
pada kedua properti Length dan Error dideklarasikan private:
// Menambahkan properti Length dan Error read-only pada
ArrayGagalHalus.
using System;
class ArrayGagalHalus
{
int[] a; // referensi ke array
int Panjang; // Panjang array
// Mengkonstruksi
array dengan ukuran tertentu.
public ArrayGagalHalus(int ukuran)
{
a = new int[ukuran];
Panjang =
ukuran;
}
// sebuah properti
read-only, implementasi-diri, Length.
public int Length { get; private set; }
// sebuah properti
read-only, implementasi-diri, Error.
public bool Error { get; private set; }
// Ini adalah
indekser untuk ArrayGagalHalus.
public int this[int indeks]
{
// Ini adalah
aksesor get.
get
{
if (ok(indeks))
{
Error = false;
return a[indeks];
}
else
{
Error = true;
return 0;
}
}
// Ini adalah
aksesor set.
set
{
if (ok(indeks))
{
a[indeks] = value;
Error =
false;
}
else Error = true;
}
}
// Menghasilkan
true jika indeks di dalam batas.
private bool ok(int indeks)
{
if (indeks >= 0 & indeks <
Length) return true;
return false;
}
}
// Mendemonstrasikan array gagal-halus terperbaiki
class DemoGHAkhir
{
static void Main()
{
ArrayGagalHalus
fs = new ArrayGagalHalus(5);
// Menggunakan
properti Error.
for (int i = 0; i < fs.Length + 1; i++)
{
fs[i] = i *
10;
if (fs.Error)
Console.WriteLine("Error dengan indeks " + i);
}
}
}
Menggunakan
Indekser Dan Properti
Meskipun
beberapa contoh terdahulu telah mendemonstrasikan mekanisme dasar dari indekser
dan properti, kekuatan penuh dari keduanya belum ditunjukkan. Untuk
menyimpulkan bab ini, sebuah kelas, RentangArray,
dikembangkan yang menggunakan indekser dan properti untuk menciptakan sebuah
tipe array dimana di dalamnya rentang indeks ditentukan oleh programer.
Seperti Anda
ketahui, dalam C# semua array berindeks mulai dari nol. Namun, pada beberapa
aplikasi, diubutuhkan sebuah array yang membolehkan pengindeksan mulai dari
titik sembarang. Sebagai contoh, pada beberapa situasi diinginkan sebuah array
dengan indeks mulai dari 1. Dalam situasi lain, dibutuhkan sebuah array dengan
indeks negatif, misalnya dari -5 sampai 5. Kelas RentangArray yang dikembangkan di sini membolehkan pengindeksan
seperti ini.
Dengan
menggunakan RentangArray, Anda dapat menuliskan kode semacam ini:
RentangArray ra
= new RentangArray (-5, 10); // indeks array dari -5 sampai 10
for(int
i=-5; i <= 10; i++) ra[i] = i; // indeks dari -5 sampai 10
Seperti Anda
tebak, baris pertama mengkonstruksi sebuah objek RentangArray dengan indeks -5 sampai 10. Argumen pertama
menspesifikasi indeks awal. Argumen kedua menspesifikasi indeks akhir. Begitu ra dikonstruksi, ia dapat diindeks dari
-5 sampai 10.
Kelas RentangArray ditampilkan di sini,
bersama dengan DemoRentangArray,
yang mendemonstrasikan array. Seperti diimplementasikan di sini, RentangArray mendukung array int, tetapi Anda dapat mengganti tipe
datanya, jika diperlukan.
/* Menciptakan kelas rentang array.
Kelas RentangArray
membolehkan pengindeksan dimulai dari
nilai tertentu
selain 0. Ketika Anda menciptakan sebuah RentangArray,
Anda perlu
menspesifikasi indeks awal dan indeks akhir. Indeks
negatif juga bisa
digunakan. Sebagai contoh, Anda dapat menciptakan
array dengan indeks
mulai dari -5 sampai 5, 1 sampai 10, atau 50 sampai 56.
*/
using System;
class RentangArray {
// data private.
int[] a; // referensi ke array
int batasBawah; // indeks terkecil
int batasAtas; // indeks terbesar
// properti Length,
read-only.
public int Length { get;
private set; }
// properti Error,
read-only.
public bool Error { get;
private set; }
// menciptakan array
dengan ukuran tertentu.
public RentangArray(int
bawah, int atas)
{
atas++;
if (atas <= bawah)
{
Console.WriteLine("Indeks
tak-valid");
atas = 1; //
menciptakan array minimal
bawah = 0;
}
a = new int[atas - bawah];
Length = atas -
bawah;
batasBawah = bawah;
batasAtas = --atas;
}
// Ini adalah
indekser untuk RentangArray.
public int this[int indeks]
{
// Ini adalah
aksesor get.
get
{
if (ok(indeks))
{
Error = false;
return a[indeks - batasBawah];
}
else
{
Error = true;
return 0;
}
}
// Ini adalah
aksesor set.
set
{
if (ok(indeks))
{
a[indeks -
batasBawah] = value;
Error = false;
}
else Error = true;
}
}
// Menghasilkan true
jika indeks di dalam batas.
private bool ok(int
indeks)
{
if (indeks >= batasBawah &
indeks <= batasAtas) return true;
return false;
}
}
// Demonstrasi array rentang-indeks.
class DemoRentangArray
{
static void Main()
{
RentangArray ra
= new RentangArray(-5, 5);
RentangArray
ra2 = new RentangArray(1, 10);
RentangArray
ra3 = new RentangArray(-20, -12);
// Demonstrasi
ra.
Console.WriteLine("Panjang dari ra: " + ra.Length);
for (int i = -5; i <= 5; i++)
ra[i] = i;
Console.Write("Isi dari ra: ");
for (int i = -5; i <= 5; i++)
Console.Write(ra[i] + " ");
Console.WriteLine("\n");
// Demonstrasi
ra2.
Console.WriteLine("Panjang dari ra2: " + ra2.Length);
for (int i = 1; i <= 10; i++)
ra2[i] = i;
Console.Write("Isi dari ra2: ");
for (int i = 1; i <= 10; i++)
Console.Write(ra2[i] + " ");
Console.WriteLine("\n");
// Demonstrasi
ra3.
Console.WriteLine("Panjang dari ra3: " + ra3.Length);
for (int i = -20; i <= -12; i++)
ra3[i] = i;
Console.Write("Panjang dari ra3: ");
for (int i = -20; i <= -12; i++)
Console.Write(ra3[i] + " ");
Console.WriteLine("\n");
}
}
Keluaran program
ditampilkan di sini:
Panjang dari ra: 11
Isi dari ra: -5 -4 -3 -2 -1 0 1 2 3 4 5
Panjang dari ra2: 10
Isi dari ra2: 1 2 3 4 5 6 7 8 9 10
Panjang dari ra3: 9
Panjang dari ra3: -20 -19 -18 -17 -16 -15 -14 -13 -12
Seperti
ditegaskan keluran, objek bertipe RentangArray
dapat diindeks bukan hanya dari nol. Akan ditengok lebih dekat tentang
bagaimana RentangArray
diimplementasikan.
RentangArray dimulai dengan pendefinisan beberapa
variabel instans:
// data private.
int[] a; // referensi ke array
int batasBawah; // indeks
terkecil
int batasAtas; // indeks terbesar
Array untuk
penyimpanan ditunjuk oleh a. Array
ini dialokasikan oleh konstruktor RentangArray.
Indeks dari batas bawah array disimpan di dalam batasBawah, dan indeks dari batas atas array disimpan di dalam batasAtas.
Selanjutnya,
properti read-only Length dan Error dideklarasikan:
// properti Length,
read-only.
public int Length { get; private set; }
// properti Error,
read-only.
public bool Error
{ get; private set; }
Perhatikan bahwa
untuk kedua properti, aksesor set
dideklarasikan private. Seperti
dijelaskan sebelumnya pada bab ini, ini menghasilkan properti read-only.
Konstruktor RentangArray ditampilkan di sini:
// menciptakan array dengan
ukuran tertentu.
public RentangArray(int bawah, int atas)
{
atas++;
if
(atas <= bawah)
{
Console.WriteLine("Indeks tak-valid");
atas = 1; // menciptakan array minimal
bawah = 0;
}
a = new
int[atas - bawah];
Length = atas - bawah;
batasBawah = bawah;
batasAtas = --atas;
}
RentangArray dikonstruksi dengan melewatkan indeks
batas bawah di dalam bawah dan
indeks batas atas di dalam atas.
Nilai dari atas kemudian diinkremen karena indeks yang dispesifikasi inklusif.
Selanjutnya, pemeriksaan dilakukan untuk memastikan bahwa indeks atas lebih
besar dari indeks bawah. Jika tidak, error akan dilaporkan dan sebuah array
satu-elemen diciptakan. Berikutnya, penyimpanan untuk array dialokasikan dan
ditugaskan kepada a. Kemudian
properti Length ditetapkan sama dengan jumlah elemen di dalam array. Terakhir, batasBawah dan batasAtas ditetapkan.
Berikutnya, RentangArray mengimplementasikan
indeksernya, seperti ditunjukkan di sini:
// Ini adalah indekser untuk
RentangArray.
public int this[int indeks]
{
// Ini adalah aksesor get.
get
{
if
(ok(indeks))
{
Error = false;
return
a[indeks - batasBawah];
}
else
{
Error = true;
return
0;
}
}
// Ini adalah aksesor set.
set
{
if
(ok(indeks))
{
a[indeks - batasBawah] = value;
Error = false;
}
else
Error = true;
}
}
Indekser ini
sama dengan yang digunakan oleh ArrayGagalHalus,
dengan satu pengecualian. Perhatikan ekspresi yang mengindeks a berikut:
indeks - batasBawah
Ekspresi ini
mentransformasikan indeks yang dilewatkan di dalam indeks ke dalam indeks berbasis-nol. Ekspresi ini berkerja manakala
batasBawah positi, negatif, atau
nol.
Metode ok() ditampilkan di sini:
The ok( ) method is shown here:
private bool ok(int indeks)
{
if
(indeks >= batasBawah & indeks <= batasAtas) return true;
return
false;
}
Ini sama dengan
yang digunakan oleh ArrayGagalHalus
kecuali bahwa rentang diperiksa dengan mengujinya terhadap nilai-nilai di dalam
batasBawah dan batasAtas.
No comments:
Post a Comment