如何在 C # 中使用类别别名,而不必向每个使用该类别的文件添加一行代码?

我想为一个类名创建一个别名。下面的语法将是完美的:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
...
}


public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

但无法编译。


例子

注意 此示例仅为方便起见而提供。不要试图通过建议改变整个系统的设计来解决这个特定的问题。这个例子的存在或缺乏并没有改变最初的问题。

一些现有代码依赖于静态类的存在:

public static class ColorScheme
{
...
}

此配色方案是 Outlook2003配色方案。我想介绍一个 Outlook2007配色方案,同时保留 Outlook2003配色方案:

public static class Outlook2003ColorScheme
{
...
}


public static class Outlook2007ColorScheme
{
...
}

但是我仍然要面对这样一个事实,即代码依赖于一个名为 ColorScheme的静态类的存在。我的第一个想法是创建一个从 Outlook2003Outlook2007继承的 ColorScheme类:

public static class ColorScheme : Outlook2007ColorScheme
{
}

但是不能从静态类继承。

我的下一个想法是创建静态的 ColorScheme类,但是使 Outlook2003ColorSchemeOutlook2007ColorScheme类成为非静态的。然后,静态 ColorScheme类中的一个静态变量可以指向“真正的”配色方案:

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


private class CustomColorScheme
{
...
}


private class Outlook2008ColorScheme : CustomColorScheme
{
...
}


private class Outlook2003ColorScheme : CustomColorScheme
{
...
}

但这需要我将一个完全由只读静态 Colors 组成的类转换为可重写属性,然后我的 ColorScheme类需要将30个不同的属性 getter 插入到所包含的对象中。

打字太多了。

所以我的下一个想法就是给这个班起个别名:

public static ColorScheme = Outlook2007ColorScheme;

但是没有编译。

如何将静态类别名为另一个名称?


更新: 是否有人可以添加答案 “你不能在 C # 中这样做”,这样我就可以将其标记为已接受的答案。任何想要得到同一个问题答案的人都会发现这个问题、公认的答案,以及一些可能有用,也可能没有用的变通方法。

我只想结束这个问题。

97470 次浏览

You can’t. The next best thing you can do is have using declarations in the files that use the class.

For example, you could rewrite the dependent code using an import alias (as a quasi-typedef substitute):

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

Unfortunately this needs to go into every scope/file that uses the name.

I therefore don't know if this is practical in your case.

try this:

using ColorScheme=[fully qualified].Outlook2007ColorScheme

You want a (Factory|Singleton), depending on your requirements. The premise is to make it so that the client code doesn't have to know which color scheme it is getting. If the color scheme should be application wide, a singleton should be fine. If you may use a different scheme in different circumstances, a Factory pattern is probably the way to go. Either way, when the color scheme needs to change, the code only has to be changed in one place.

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; }
}
}

Is it possible to change to using an interface?

Perhaps you could create an IColorScheme interface that all of the classes implement?

This would work well with the factory pattern as shown by Chris Marasti-Georg

You can make an alias for your class by adding this line of code:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;

You cannot alias a class name in C#.

There are things you can do that are not aliasing a class name in C#.

But to answer the original question: you cannot alias a class name in C#.


Update: People are confused why using doesn't work. Example:

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) { ... }
}

And everything works. Now i want to create a new class, and alias ColorScheme to it (so that no code needs to be modified):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;


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

Ohh, i'm sorry. This code doesn't compile:

enter image description here

My question was how to alias a class in C#. It cannot be done. There are things i can do that are not aliasing a class name in C#:

  • change everyone who depends on ColorScheme to using ColorScheme instead (code change workaround because i cannot alias)
  • change everyone who depends on ColorScheme to use a factory pattern them a polymorphic class or interface (code change workaround because i cannot alias)

But these workarounds involve breaking existing code: not an option.

If people depend on the presence of a ColorScheme class, i have to actually copy/paste a ColorScheme class.

In other words: i cannot alias a class name in C#.

This contrasts with other object oriented languages, where i could define the alias:

ColorScheme = Outlook2007ColorScheme

and i'd be done.

Aliasing the way that you would like to do it will not work in C#. This is because aliasing is done through the using directive, which is limited to the file/namespace in question. If you have 50 files that use the old class name, that will mean 50 places to update.

That said, I think there is an easy solution to make your code change as minimal as possible. Make the ColorScheme class a facade for your calls to the actual classes with the implementation, and use the using in that file to determine which ColorScheme you use.

In other words, do this:

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);
}
}

Then in your code behind, change nothing:

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

You can then update the values of ColorScheme by updating one line of code (using CurrentColorScheme = Outlook2008ColorScheme;).

A couple concerns here:

  • Every new method or property definition will then need to be added in two places, to the ColorScheme class and to the Outlook2007ColorScheme class. This is extra work, but if this is true legacy code, it shouldn't be a frequent occurence. As a bonus, the code in ColorScheme is so simple that any possible bug is very obvious.
  • This use of static classes doesn't seem natural to me; I probably would try to refactor the legacy code to do this differently, but I understand too that your situation may not allow that.
  • If you already have a ColorScheme class that you're replacing, this approach and any other could be a problem. I would advise that you rename that class to something like ColorSchemeOld, and then access it through using CurrentColorScheme = ColorSchemeOld;.

I suppose you can always inherit from the base class with nothing added

public class Child : MyReallyReallyLongNamedClass {}

UPDATE

But if you have the capability of refactoring the class itself: A class name is usually unnecessarily long due to lack of namespaces.

If you see cases as ApiLoginUser, DataBaseUser, WebPortalLoginUser, is usually indication of lack of namespace due the fear that the name User might conflict.

In this case however, you can use namespace alias ,as it has been pointed out in above posts

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);

Note how the class names are all User, but in different namespaces. Quoting PEP-20: Zen of Python:

Namespaces are one honking great idea -- let's do more of those!

Hope this helps

It's a very late partial answer - but if you define the same class 'ColorScheme', in the same namespace 'Outlook', but in separate assemblies, one called Outlook2003 and the other Outlook2007, then all you need to do is reference the appropriate assembly.

I'm adding this comment for users finding this long after OP accepted their "answer". Aliasing in C# works by specifying the class name using it's fully qualified namespace. One defined, the alias name can be used within it's scope. Example.

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
}


}

Apologies for the quickly typed code but hopefully it explains how this should be implemented so that users aren't mislead into believing it cannot be done in C#.

The best way I've found to simulate alias in C# is inheritance.

Create a new class that inherits from the original class:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
...
}


public class MyName
: LongClassNameOrOneThatContainsVersionOrDomainSpecificName
{


}

The only thing that you would need to be careful is the constructor. You need to provide a a constructor for MyName class.

public class MyName
: LongClassNameOrOneThatContainsVersionOrDomainSpecificName
{
public MyName(T1 param1, T2 param2) : base(param1, param2) {}
}

In this example I'm using T1 and T2 as generic types, since I don't know the constructor for your LongClassNameOrOneThatContainsVersionOrDomainSpecificName class.

Beware, though, that this is not alias. Doing this to you application might run into some issues or problems. You might need to create some extra code to check for types, or even overload some operators.