Bagaimana cara membuat alias nama kelas di C #, tanpa harus menambahkan baris kode ke setiap file yang menggunakan kelas tersebut?

88

Saya ingin membuat alias untuk nama kelas. Sintaks berikut akan menjadi sempurna:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

tetapi tidak dapat dikompilasi.


Contoh

Catatan Contoh ini diberikan hanya untuk kenyamanan. Jangan mencoba memecahkan masalah khusus ini dengan menyarankan untuk mengubah desain seluruh sistem. Ada atau tidaknya contoh ini tidak mengubah pertanyaan awal.

Beberapa kode yang ada bergantung pada keberadaan kelas statis:

public static class ColorScheme
{
   ...
}

Skema warna ini adalah skema warna Outlook 2003. saya ingin memperkenalkan skema warna Outlook 2007, dengan tetap mempertahankan skema warna Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Tetapi saya masih dihadapkan pada fakta bahwa kode tersebut bergantung pada keberadaan kelas statis yang disebut ColorScheme. Pikiran pertama saya adalah membuat ColorSchemekelas yang akan saya warisi dari salah satu Outlook2003atau Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

tetapi Anda tidak dapat mewarisi dari kelas statis.

Pikiran saya selanjutnya adalah membuat ColorSchemekelas statis , tetapi membuat Outlook2003ColorSchemedan Outlook2007ColorSchemekelas non-statis. Kemudian variabel statis di ColorSchemekelas statis dapat mengarah ke salah satu skema warna "benar":

public static class ColorScheme
{
    private static CustomColorScheme = new Outlook2007ColorScheme();
    ...
}

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

tetapi itu akan mengharuskan saya untuk mengubah kelas yang terdiri dari keseluruhan Warna statis yang dapat dibaca menjadi properti yang dapat diganti, dan kemudian ColorSchemekelas saya harus memiliki 30 pengambil properti berbeda yang dimasukkan ke dalam objek yang terkandung.

Itu terlalu banyak mengetik.

Jadi pikiran saya selanjutnya adalah membuat alias kelas:

public static ColorScheme = Outlook2007ColorScheme;

Tapi itu tidak bisa dikompilasi.

Bagaimana cara membuat alias kelas statis menjadi nama lain?


Pembaruan: Bisakah seseorang menambahkan jawaban "Anda tidak dapat melakukan ini di C #" , jadi saya dapat menandainya sebagai jawaban yang diterima. Orang lain yang menginginkan jawaban untuk pertanyaan yang sama akan menemukan pertanyaan ini, jawaban yang diterima, dan sejumlah solusi yang mungkin, atau mungkin tidak, berguna.

Saya hanya ingin menutup pertanyaan ini.

Ian Boyd
sumber
Anda mungkin juga menerima jawaban Chris, bahkan jika Anda tidak ingin menerapkannya
devio
2
Ini bukan jawabannya, ini solusi. Jawabannya adalah Anda tidak bisa - setidaknya sampai seseorang datang dan memposting sintaks yang sebenarnya untuk melakukannya.
Ian Boyd
1
Bagi siapa pun yang datang ke sini, jawaban yang diterima salah karena komentar berperingkat tertinggi berfungsi dengan baik di proyek VS 2010 dan VS 2017 c # yang saya kerjakan. Namespace yang sepenuhnya memenuhi syarat harus digunakan untuk menentukan kelas saat menyiapkan alias, tetapi setelah penyiapan, alias berfungsi dalam cakupan yang ditentukan.
J-Americano
Saya harus membaca jawaban Ian dan komentarnya dengan sangat rinci sebelum saya memahami apa yang dia cari. Dia ingin mendeklarasikan alias kelas di satu tempat , daripada harus menambahkannya ke bagian atas setiap file yang mereferensikan kelas. Saya tidak mengetahui ada bahasa yang diketik kuat yang mendukung ini. (Jika seseorang mengetahui bahasa seperti itu, saya ingin mengetahuinya.) Saya telah mengedit judulnya agar lebih jelas.
ToolmakerSteve
BTW, untuk siapa saja yang mencoba melakukan sesuatu yang serupa: jika ini adalah kelas yang Anda definisikan, maka pendekatan C # adalah dengan mendefinisikan an interface, yang diimplementasikan oleh semua kelas Anda. Seperti yang disebutkan dalam jawaban chills42 . Anda kemudian dapat menentukan "layanan" atau "pabrik" yang mengembalikan objek yang mengimplementasikan antarmuka itu, bergantung pada keadaan saat ini (misalnya platform / OS) atau pada file konfigurasi.
ToolmakerSteve

Jawaban:

131

Tidak boleh . Hal terbaik berikutnya yang dapat Anda lakukan adalah memiliki usingdeklarasi di file yang menggunakan kelas tersebut.

Misalnya, Anda dapat menulis ulang kode dependen menggunakan alias import (sebagai typedefpengganti semu ):

using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;

Sayangnya ini harus masuk ke setiap ruang lingkup / file yang menggunakan nama tersebut.

Oleh karena itu, saya tidak tahu apakah ini praktis dalam kasus Anda.

Konrad Rudolph
sumber
9
Jika itu bisa pergi di bagian atas file yang berisi kelas asli: itu akan bagus. Tetapi usingharus ditambahkan ke semua kode yang rusak. Dan itu juga meniadakan nilai memiliki satu alias, yang memungkinkan saya mengalihkan semua pengguna dari ColorSchemekelas yang ada untuk menggunakan kelas baru - tanpa perubahan. Dengan kata lain: saya ingin memasukkan ColorSchemekelas ke kelas lain.
Ian Boyd
Apakah ada cara untuk mencapai yang sama dan menyebarkan alias dengan warisan. yaitu semua kelas yang memperluas MyClass akan dapat menggunakan ColorScheme daripada the.Fully.Qualified ... ColorScheme dengan hanya menambahkan pernyataan using di file sumber MyClass?
Florian Burel
Nah, itu sangat praktis untuk kasus saya. Akhirnya C # akan berhenti menggambar jalur file saya.
ElDoRado1239
25

Anda dapat membuat alias untuk kelas Anda dengan menambahkan baris kode ini:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;
mohammedn
sumber
Nama 'ColorScheme' tidak ada dalam konteks saat ini
Ian Boyd
7
Anda membutuhkan Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
Saya pikir di C # hanya bisa ruang nama alias (bukan kelas) dengan cara ini, di mana di VB.Net Anda dapat menggunakan ruang nama alias atau kelas Imports. Apakah aku salah?
Nick
Anda tidak memerlukan nama yang sepenuhnya memenuhi syarat jika Anda meletakkan usingdirektif di dalam namespace itu, misalnya ketika Anda membutuhkan alias dari kelas Anda sendiri.
Elvedin Hamzagic
12

Anda menginginkan ( Factory | Singleton ), tergantung pada kebutuhan Anda. Premisnya adalah membuatnya sehingga kode klien tidak harus tahu skema warna mana yang didapatnya. Jika skema warna harus diterapkan secara luas, satu warna tunggal sudah cukup. Jika Anda dapat menggunakan skema yang berbeda dalam keadaan yang berbeda, pola Pabrik mungkin merupakan cara yang tepat. Bagaimanapun juga, ketika skema warna perlu diubah, kode hanya perlu diubah di satu tempat.

public interface ColorScheme {
    Color TitleBar { get; }
    Color Background{ get; }
    ...
}

public static class ColorSchemeFactory {

    private static ColorScheme scheme = new Outlook2007ColorScheme();

    public static ColorScheme GetColorScheme() { //Add applicable arguments
        return scheme;
    }
}

public class Outlook2003ColorScheme: ColorScheme {
   public Color TitleBar {
       get { return Color.LightBlue; }
   }

    public Color Background {
        get { return Color.Gray; }
    }
}

public class Outlook2007ColorScheme: ColorScheme {
   public Color TitleBar {
       get { return Color.Blue; }
   }

    public Color Background {
        get { return Color.White; }
    }
}
Chris Marasti-Georg
sumber
Ini terlihat seperti bukan pabrik dan lebih merupakan upaya yang lemah pada pola tunggal. Pabrik akan lebih cenderung untuk membuat parameter metode pembuatan; Anda akan memiliki sesuatu yang lebih seperti: public static ColorScheme GetColorScheme (deskripsi string);
OwenP
Benar - ide dasarnya adalah memastikan bahwa saat Office 2012 keluar, kode hanya perlu diubah di 1 tempat.
Chris Marasti-Georg
1
Ini pasti berhasil, tetapi tentu saja ini merupakan solusi perusahaan-y untuk masalah sederhana.
Ian Boyd
11

Anda tidak dapat membuat alias nama kelas di C #.

Ada hal-hal yang dapat Anda lakukan yang tidak aliasing nama kelas di C #.

Tetapi untuk menjawab pertanyaan awal: Anda tidak dapat membuat alias nama kelas di C #.


Pembaruan: Orang-orang bingung mengapa usingtidak berfungsi. Contoh:

Form1.cs

private void button1_Click(object sender, EventArgs e)
{
   this.BackColor = ColorScheme.ApplyColorScheme(this.BackColor);
}

ColorScheme.cs

class ColorScheme
{
    public static Color ApplyColorScheme(Color c) { ... }
}

Dan semuanya bekerja. Sekarang saya ingin membuat kelas baru , dan alias ColorScheme untuk itu (sehingga tidak ada kode yang perlu diubah ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

class Outlook2007ColorScheme
{
    public static Color ApplyColorScheme(Color c) { ... }
}

Ohh, maafkan aku. Kode ini tidak dapat dikompilasi:

masukkan deskripsi gambar di sini

Pertanyaan saya adalah bagaimana membuat alias kelas di C #. Itu tidak bisa dilakukan. Ada hal-hal yang dapat saya lakukan yang tidak menggunakan nama kelas di C #:

  • perubahan setiap orang yang tergantung pada ColorSchemeke using ColorSchemebukan (kode perubahan solusi karena saya tidak bisa alias)
  • ubah semua orang yang bergantung pada ColorSchemeuntuk menggunakan pola pabrik menjadi kelas atau antarmuka polimorfik (ubah kode solusi karena saya tidak bisa alias)

Tetapi solusi ini melibatkan pemecahan kode yang ada: bukan opsi.

Jika orang bergantung pada keberadaan ColorSchemekelas, saya harus benar-benar menyalin / menempelkan ColorSchemekelas.

Dengan kata lain: saya tidak bisa membuat alias nama kelas di C #.

Ini kontras dengan bahasa berorientasi objek lainnya, di mana saya dapat mendefinisikan alias:

ColorScheme = Outlook2007ColorScheme

dan saya akan selesai.

Ian Boyd
sumber
22
Anda benar-benar dapat membuat alias nama kelas di C #. "menggunakan <alias_name> = <fully_qualified_name>;"
clemahieu
8
LIke @clemahieu berkata, Anda benar-benar dapat membuat alias nama kelas, Anda hanya perlu menggunakan nama yang memenuhi syarat. Selain itu, jika aliasing Anda adalah kelas generik, Anda dapat menambahkan qualifier kelas generik. Misalnya: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Dan Morphis
11
Suara negatif - Anda telah menyatakan "Anda tidak dapat membuat alias nama kelas di C #." Kamu bisa. Apa yang tidak dapat Anda lakukan adalah alias kelas dengan cara yang Anda inginkan - yang merupakan persyaratan yang dapat dibenarkan, tetapi pernyataan Anda salah.
Tom W
8
Seperti yang ditunjukkan oleh beberapa poster, penggunaan nama yang memenuhi syarat sama sekali tidak melarang aliasing. Anda dapat membuat alias kelas. Anda hanya perlu menggunakan nama yang sepenuhnya memenuhi syarat untuk melakukannya. Anda mungkin merasa ini tidak nyaman, tetapi pernyataan 'Anda tidak dapat membuat alias nama kelas di C #' menjadi benar. Mungkin cara kerja aliasing di C # berbeda dengan yang Anda harapkan. Tidak apa-apa - jika itu masalahnya, nyatakan itu. Tetapi Anda dapat membuat alias nama kelas di C # karena spesifikasi menyatakan bahwa Anda dapat melakukannya, sesuai dengan definisi yang diberikan.
Tom W
5
Saya suka bagaimana kami, programmer, membuat pernyataan yang tersirat. Apa yang sebenarnya dikatakan Ian adalah bahwa C # itu bodoh dan rusak karena ia tidak dapat melakukan hal dasar sederhana yang ingin dilakukan dan harus dilakukan oleh siapa pun. Dia benar - apakah semantik tertentu membuat Anda bahagia atau tidak.
IQpierce
10

coba ini:

using ColorScheme=[fully qualified].Outlook2007ColorScheme
dpurrington.dll
sumber
Nama 'ColorScheme' tidak ada dalam konteks saat ini
Ian Boyd
2
Anda membutuhkan Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
6

Saya menambahkan komentar ini untuk pengguna yang menemukan ini lama setelah OP menerima "jawaban" mereka. Aliasing di C # bekerja dengan menentukan nama kelas menggunakan namespace yang memenuhi syarat. Setelah ditentukan, nama alias dapat digunakan dalam cakupannya. Contoh.

using aliasClass = Fully.Qualified.Namespace.Example;
//Example being the class in the Fully.Qualified.Namespace

public class Test{

  public void Test_Function(){

    aliasClass.DoStuff();
    //aliasClass here representing the Example class thus aliasing
    //aliasClass will be in scope for all code in my Test.cs file
  }

}

Permintaan maaf untuk kode yang diketik dengan cepat tapi mudah-mudahan ini menjelaskan bagaimana ini harus diterapkan sehingga pengguna tidak disesatkan menjadi percaya itu tidak dapat dilakukan di C #.

J-Americano
sumber
Ini akan menjadi lebih jelas jika Anda menunjukkan deklarasi dari kelas lain: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
ToolmakerSteve
1
Untuk lebih jelasnya, ini berbeda dengan yang dicari Ian. Ian memiliki situasi di mana dia tidak dapat (atau tidak ingin) mengubah file sumber yang merujuk ke sebuah kelas. Dia menginginkan cara untuk membuat perubahan hanya di satu tempat di aplikasi atau perpustakaannya , menghasilkan apa yang tampak seperti kelas dengan nama yang diinginkan, yang dapat digunakan oleh semua kode lain [tanpa harus menambahkan pernyataan "menggunakan" itu ke beberapa sumber file - misalnya sumber tersebut mungkin tidak tersedia untuk diubah].
ToolmakerSteve
4

Aliasing seperti yang Anda inginkan tidak akan berhasil di C #. Ini karena aliasing dilakukan melalui usingdirektif, yang dibatasi pada file / namespace yang dimaksud. Jika Anda memiliki 50 file yang menggunakan nama kelas lama, itu berarti 50 tempat untuk memperbarui.

Karena itu, menurut saya ada solusi mudah untuk membuat perubahan kode Anda seminimal mungkin. Jadikan ColorSchemekelas sebagai fasad untuk panggilan Anda ke kelas yang sebenarnya dengan implementasi, dan gunakan usingdalam file tersebut untuk menentukan yang ColorSchemeAnda gunakan.

Dengan kata lain, lakukan ini:

using CurrentColorScheme = Outlook2007ColorScheme;
public static class ColorScheme
{
   public static Color ApplyColorScheme(Color c)
   {
       return CurrentColorScheme.ApplyColorScheme(c);
   }
   public static Something DoSomethingElse(Param a, Param b)
   {
       return CurrentColorScheme.DoSomethingElse(a, b);
   }
}

Kemudian di belakang kode Anda, tidak ada perubahan apa pun:

private void button1_Click(object sender, EventArgs e)
{
   this.BackColor = ColorScheme.ApplyColorScheme(this.BackColor);
}

Anda kemudian dapat memperbarui nilai ColorSchemedengan memperbarui satu baris kode ( using CurrentColorScheme = Outlook2008ColorScheme;).

Beberapa masalah di sini:

  • Setiap metode baru atau definisi properti kemudian perlu ditambahkan di dua tempat, ke ColorSchemekelas dan ke Outlook2007ColorSchemekelas. Ini adalah pekerjaan ekstra, tetapi jika ini adalah kode warisan yang sebenarnya, ini seharusnya tidak sering terjadi. Sebagai bonus, kode di ColorSchemedalamnya sangat sederhana sehingga setiap kemungkinan bug sangat jelas terlihat.
  • Penggunaan kelas statis ini tampaknya tidak alami bagi saya; Saya mungkin akan mencoba memfaktor ulang kode lama untuk melakukan ini secara berbeda, tetapi saya juga mengerti bahwa situasi Anda mungkin tidak mengizinkannya.
  • Jika Anda sudah memiliki ColorSchemekelas yang Anda gantikan, pendekatan ini dan lainnya bisa menjadi masalah. Saya akan menyarankan agar Anda mengganti nama kelas itu menjadi seperti ColorSchemeOld, dan kemudian mengaksesnya melalui using CurrentColorScheme = ColorSchemeOld;.
Timothy
sumber
3

Saya kira Anda selalu dapat mewarisi dari kelas dasar tanpa ada yang ditambahkan

public class Child : MyReallyReallyLongNamedClass {}

MEMPERBARUI

Tetapi jika Anda memiliki kemampuan refactoring classitu sendiri: Sebuah nama kelas biasanya tidak perlu panjang karena kurangnya namespaces.

Jika Anda melihat kasus seperti ApiLoginUser, DataBaseUser, WebPortalLoginUser, biasanya indikasi kurangnya namespacekarena takut bahwa nama Userkonflik kekuatan.

Namun dalam kasus ini, Anda dapat menggunakan namespacealias , seperti yang telah ditunjukkan pada posting di atas

using LoginApi = MyCompany.Api.Login;
using AuthDB = MyCompany.DataBase.Auth;
using ViewModels = MyCompany.BananasPortal.Models;

// ...
AuthDB.User dbUser;
using ( var ctxt = new AuthDB.AuthContext() )
{
    dbUser = ctxt.Users.Find(userId);
}

var apiUser = new LoginApi.Models.User {
        Username = dbUser.EmailAddess,
        Password = "*****"
    };

LoginApi.UserSession apiUserSession = await LoginApi.Login(apiUser);
var vm = new ViewModels.User(apiUserSession.User.Details);
return View(vm);

Perhatikan bagaimana semua classnama itu User, tetapi dalam namespaces yang berbeda . Mengutip PEP-20: Zen of Python :

Namespaces adalah salah satu ide bagus - mari kita lakukan lebih banyak lagi!

Semoga ini membantu

percebus
sumber
2
selalu, kecuali jika Anda tidak dapat: misalnya kelas tertutup
mikus
tapi itu tidak akan berhasil dalam banyak kasus. misalnya kelas publik MyList: List {} - jika nanti Anda mencoba MyList xyz = something.ToList (); Anda akan terjebak.
Offler
@Offler Anda dapat (dan mungkin harus) menggunakan salah satu newkata kunci untuk metode tersebut atau bahkan membuat ExtensionMethods Anda sendiri, bukan? Dalam hal apapun itu adalah pendapat kuat saya bahwa Anda harus selalu menggunakan kelas Vanilla Collection (yaitu Dictionary, List, IEnumerable, IQuerable, dll.) Dengan Model / ViewModels / POCO kustom. Seperti yang dinyatakan
Mvc
@percebus tidak berfungsi di semua kasus. Saya mencoba untuk mengubah kode vintage dimana bagian menggunakan api tidak lagi didukung ke yang lebih baru. kode transformasi durign akan diubah oleh orang lain dan harus tetap dapat dijalankan - jadi keduanya harus dapat digunakan sekarang. mengubah Things lebih dari 700.000 LOC (tanpa komentar) dan membiarkannya tetap dapat dijalankan akan lebih mudah, jika alias gaya c ++ dimungkinkan - dan Anda hanya perlu satu tempat dalam file untuk mengganti kelas alias dengan implementasi dari salah satu dari mereka.
Offler
RE-POST untuk EDIT @Offler Untuk apa yang Anda gambarkan tentang suara yang Anda perlukan seperti Pabrik dengan antarmuka. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Juga, Anda mungkin ingin melihat Injeksi Ketergantungan
percebus
2

Apakah mungkin untuk mengubah menggunakan antarmuka?

Mungkin Anda dapat membuat IColorSchemeantarmuka yang diterapkan oleh semua kelas?

Ini akan bekerja dengan baik dengan pola pabrik seperti yang ditunjukkan oleh Chris Marasti-Georg

menggigil 42
sumber
Bisa jadi, tapi saya tidak akan menghabiskan waktu untuk itu daripada mengganti nama kelas yang merupakan skema warna "saat ini" untuk digunakan.
Ian Boyd
0

Ini adalah jawaban parsial yang sangat terlambat - tetapi jika Anda menentukan kelas yang sama 'ColorScheme', di namespace yang sama 'Outlook', tetapi dalam rakitan terpisah, yang disebut Outlook2003 dan yang lainnya Outlook2007, maka yang perlu Anda lakukan hanyalah mereferensikan perakitan yang sesuai .

Mark Farmiloe
sumber