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

Posted

技术标签:

【中文标题】如何在 C# 中为类名起别名,而不必向使用该类的每个文件添加一行代码?【英文标题】:How do I alias a class name in C#, without having to add a line of code to every file that uses the class? 【发布时间】:2010-09-19 15:27:42 【问题描述】:

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

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName

   ...


public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

但它不会编译。


示例

注意 本示例仅为方便起见而提供。不要试图通过建议改变整个系统的设计来解决这个特定的问题。此示例的存在或缺失不会改变原始问题。

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

public static class ColorScheme

   ...

此配色方案是 Outlook 2003 配色方案。我想引入 Outlook 2007 配色方案,同时保留 Outlook 2003 配色方案:

public static class Outlook2003ColorScheme

   ...


public static class Outlook2007ColorScheme

   ...

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

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 

   ...

但这需要我将一个完全由只读静态颜色组成的类转换为可覆盖的属性,然后我的 ColorScheme 类需要将 30 个不同的属性 getter 转换为包含的对象。

打字太多了。

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

public static ColorScheme = Outlook2007ColorScheme;

但这不会编译。

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


更新:有人可以添加答案“您不能在 C# 中执行此操作”,因此我可以将其标记为已接受的答案。任何其他想要获得相同问题答案的人都会发现这个问题、已接受的答案以及许多可能有用或可能没有用的变通方法。

我只想结束这个问题。

【问题讨论】:

你不妨接受克里斯的回答,即使你不想实现它 这不是答案,而是一种解决方法。答案是你不能 - 至少在有人过来并发布实际语法来做到这一点之前。 对于任何来到这里的人来说,接受的答案都是不正确的,因为最高评价的评论在我正在处理的 VS 2010 和 VS 2017 c# 项目中工作得很好。设置别名时必须使用完全限定的命名空间来指定类,但是一旦设置别名就可以在其定义的范围内工作。 我必须详细阅读 Ian 的答案和他的 cmets,然后才能理解他在寻找什么。他想在一个地方声明一个类别名,而不是必须将它添加到每个引用该类的文件的顶部。我不知道有任何 强类型 语言支持此功能。 (如果有人知道这种语言,我很想知道。)我编辑了标题以使其更清晰。 顺便说一句,对于任何试图做类似事情的人:如果这些是您正在定义的类,那么 C# 方法是定义一个 interface,您的所有类都实现了它。如chills42's answer 中所述。然后,您可以定义一个“服务”或“工厂”,它返回一个实现该接口的对象,具体取决于当前情况(例如平台/操作系统)或配置文件。 【参考方案1】:

你不能。您可以做的下一件最好的事情是在使用该类的文件中添加using 声明。

例如,您可以使用导入别名(作为准typedef 替代)重写依赖代码:

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

不幸的是,这需要进入使用该名称的每个作用域/文件。

因此,我不知道这是否适用于您的情况。

【讨论】:

如果它可以放在包含原始类的文件的顶部:那就太好了。但是必须将using 添加到所有损坏的代码中。它还否定了具有单个别名的值,这使我可以将现有 ColorScheme 类的所有用户切换到使用新类 - 无需更改。换句话说:我想将ColorScheme 类别名为另一个类。 有没有办法实现相同并通过继承传播别名。即所有扩展 MyClass 的类都可以通过在 MyClass 源文件中添加 using 语句来使用 ColorScheme 而不是.Fully.Qualified...ColorScheme? 嗯,这对我来说非常实用。最后 C# 将停止绘制我的文件路径。【参考方案2】:

你可以通过添加这行代码为你的类创建一个别名:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;

【讨论】:

名称“ColorScheme”在当前上下文中不存在 你需要Fully.Qualified.Namespace.Of.ColorScheme 我认为在 C# 中只能以这种方式为命名空间(而不是类)命名,而在 VB.Net 中,您可以使用 Imports 为命名空间或类命名。我错了吗? 如果您将using 指令放在其命名空间中,则不需要完全限定名称,例如当您需要自己班级的别名时。【参考方案3】:

您不能在 C# 中为类名设置别名。

在 C# 中,您可以做一些不给类名起别名的事情。

但要回答最初的问题:您不能在 C# 中为类名取别名。


更新:人们很困惑为什么using 不起作用。示例:

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

一切正常。现在我想创建一个 new 类,并为其创建 alias ColorScheme(这样无需修改代码): p>

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

class Outlook2007ColorScheme

    public static Color ApplyColorScheme(Color c)  ... 

哦,对不起。此代码无法编译:

我的问题是如何在 C# 中为一个类别名。这是不可能的。我可以做的事情是 not 在 C# 中为类名起别名:

将所有依赖 ColorScheme 的人改为 using ColorScheme(代码更改解决方法,因为我无法使用别名) 将所有依赖 ColorScheme 的人更改为使用工厂模式,为他们提供多态类或接口(代码更改解决方法,因为我不能别名)

但这些变通办法涉及破坏现有代码:不是一种选择。

如果人们依赖ColorScheme 类的存在,我必须实际复制/粘贴ColorScheme 类。

换句话说:我不能在 C# 中为类名设置别名。

这与其他面向对象的语言形成对比,我可以在其中定义别名:

ColorScheme = Outlook2007ColorScheme

我已经完成了。

【讨论】:

您绝对可以在 C# 中为类名设置别名。 "使用 = ;" 就像@clemahieu 所说,你绝对可以给类名起别名,你只需要使用完全限定名。此外,如果您给泛型类起别名,则可能必须添加泛型类限定符。例如:使用 ShortName = MyNamespace.SubNamespace.GenericClass; 投反对票 - 您已声明“您不能在 C# 中为类名设置别名。”你可以。你不能做的是以想要的方式给一个类起别名 - 这是一个非常合理的要求,但你的陈述是不正确的。 正如几位发帖人所指出的,必须使用限定名绝不会禁止别名。您可以为该类设置别名。您只需使用完全限定名称即可。您可能会觉得这很不方便,但它不会使“您不能在 C# 中为类名取别名”这样的陈述为真。也许 C# 中别名的工作方式与您所期望的不同。没关系 - 如果是这样,请说明。但是您可以在 C# 中为类名起别名,因为规范声明您可以这样做,根据它提供的定义。 我喜欢我们程序员在字里行间的表达方式。 Ian 的真正意思是 C# 是愚蠢和破碎的,因为它不能做任何人都想做并且应该能够做的简单的基本事情。他是对的——具体的语义是否让你开心。【参考方案4】:

您需要 (Factory|Singleton),具体取决于您的要求。前提是要做到这一点,这样客户端代码就不必知道它得到的是哪种配色方案。如果配色方案应该适用于广泛的应用程序,那么单例应该没问题。如果您可能在不同的情况下使用不同的方案,那么工厂模式可能是要走的路。无论哪种方式,当需要更改配色方案时,只需在一处更改代码即可。

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; 
    

【讨论】:

这看起来不像是工厂,更像是对单例模式的弱尝试。工厂更有可能参数化创建方法;你会有更多类似的东西: public static ColorScheme GetColorScheme(string descriptor); 是的 - 基本想法是确保在 office 2012 发布时,代码只需更改一处。 这绝对有效,但它肯定是一个简单问题的企业级解决方案。【参考方案5】:

试试这个:

using ColorScheme=[fully qualified].Outlook2007ColorScheme

【讨论】:

名称“ColorScheme”在当前上下文中不存在 你需要Fully.Qualified.Namespace.Of.ColorScheme【参考方案6】:

我正在为在 OP 接受他们的“答案”很久之后发现这一点的用户添加此评论。 C# 中的别名通过使用其完全限定的命名空间指定类名来工作。一经定义,别名可在其范围内使用。 示例。

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
  


对快速键入的代码表示歉意,但希望它解释了如何实现这一点,以免用户误导认为它不能在 C# 中完成。

【讨论】:

如果你显示另一个类的声明,这会更清楚:namespace Fully.Qualified.Namespacepublic class Example ...public void DoStuff()..... .. 明确地说,这与 Ian 所寻求的不同。 Ian 有一种情况,他不能(或不想)更改引用某个类的源文件。他想要一种方法来仅在他的应用程序或库中的一个地方进行更改,从而生成具有所需名称的类,所有其他代码都可以使用[无需添加对多个源文件的“使用”语句 - 例如,该源可能无法更改]。【参考方案7】:

在 C# 中无法按照您希望的方式进行别名处理。这是因为别名是通过 using 指令完成的,该指令仅限于相关文件/命名空间。如果您有 50 个使用旧类名的文件,则意味着要更新 50 个位置。

也就是说,我认为有一个简单的解决方案可以使您的代码更改尽可能少。使 ColorScheme 类成为您调用具有实现的实际类的外观,并使用该文件中的 using 来确定您使用哪个 ColorScheme

换句话说,这样做:

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

然后在你的代码后面,什么都不做:

private void button1_Click(object sender, EventArgs e)

   this.BackColor = ColorScheme.ApplyColorScheme(this.BackColor);

然后您可以通过更新一行代码 (using CurrentColorScheme = Outlook2008ColorScheme;) 来更新 ColorScheme 的值。

这里有几个问题:

然后每个新方法或属性定义都需要添加到两个位置,ColorScheme 类和Outlook2007ColorScheme 类。这是额外的工作,但如果这是真正的遗留代码,它不应该经常出现。作为奖励,ColorScheme 中的代码非常简单,任何可能的错误都非常明显。 我觉得这种静态类的使用并不自然。我可能会尝试重构遗留代码以不同的方式执行此操作,但我也理解您的情况可能不允许这样做。 如果您已经有一个要替换的ColorScheme 类,那么这种方法和其他任何方法都可能会出现问题。我建议您将该类重命名为 ColorSchemeOld 之类的名称,然后通过 using CurrentColorScheme = ColorSchemeOld; 访问它。

【讨论】:

【参考方案8】:

我想你总是可以从基类继承而不添加任何东西

public class Child : MyReallyReallyLongNamedClass 

更新

但如果你有能力重构class 本身:由于缺少namespaces,类名通常不必要地过长。

如果您看到ApiLoginUserDataBaseUserWebPortalLoginUser 等案例,通常表示缺少namespace,因为担心名称User 可能会发生冲突。

但是,在这种情况下,您可以使用 namespace 别名 ,正如上面帖子中所指出的那样

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

注意class 的名称都是User,但在不同的namespaces 中。引用PEP-20: Zen of Python:

命名空间是一个很棒的主意——让我们做更多这样的事!

希望对你有帮助

【讨论】:

总是,除非你不能:例如密封类 但这在很多情况下都行不通。例如public class MyList : List - 如果您稍后尝试 MyList xyz = something.ToList();你会被卡住的。 @Offler 您可以(并且可能应该)使用new 关键字来获取此类方法,甚至想出自己的 ExtensionMethods,对吗?在任何情况下,我强烈认为您应该始终使用带有自定义 Models/ViewModels/POCO 的 vanilla Collection 类(即 Dictionary、List、IEnumerable、IQueryable 等)。正如 Mvc 所说:约定优于配置 @percebus 并非在所有情况下都有效。我尝试将使用不再支持的 api 的老式 Code whre 部件转换为较新的。 durign 转换代码将被其他人更改并且应该仍然可以运行 - 所以现在两者都应该可以使用。如果可以使用 c++ 样式的别名,那么转换超过 700.000 LOC(不带 cmets)的事物并仍然让它可运行会更容易——而且您只需要在文件中的一个位置用它们中的任何一个的实现替换别名类。 RE-POST for EDIT @Offler 对于你所描述的声音,你需要像带有接口的工厂一样的东西。 IColorScheme oColorScheme = ColorSchemeFactory.Create(); 另外,您可能想查看Dependency Injection【参考方案9】:

可以改成使用界面吗?

也许您可以创建一个所有类都实现的IColorScheme 接口?

这很适合 Chris Marasti-Georg 展示的工厂模式

【讨论】:

可能是这样,但我不会再花时间在它上面,而是重命名要使用的“当前”配色方案的类。【参考方案10】:

这是一个非常晚的部分答案 - 但如果您在相同的命名空间“Outlook”中定义相同的类“ColorScheme”,但在单独的程序集中,一个名为 Outlook2003,另一个名为 Outlook2007,那么您需要做的就是参考合适的程序集。

【讨论】:

【参考方案11】:

我发现在 C# 中模拟别名的最佳方法是继承。

创建一个继承自原始类的新类:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName

   ...


public class MyName 
    : LongClassNameOrOneThatContainsVersionOrDomainSpecificName



唯一需要注意的是构造函数。您需要为MyName 类提供一个构造函数。

public class MyName 
    : LongClassNameOrOneThatContainsVersionOrDomainSpecificName

    public MyName(T1 param1, T2 param2) : base(param1, param2)    

在此示例中,我使用 T1T2 作为泛型类型,因为我不知道您的 LongClassNameOrOneThatContainsVersionOrDomainSpecificName 类的构造函数。

请注意,这不是别名。对您的应用程序执行此操作可能会遇到一些问题。您可能需要创建一些额外的代码来检查类型,甚至重载一些运算符。

【讨论】:

以上是关于如何在 C# 中为类名起别名,而不必向使用该类的每个文件添加一行代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel Eloquent 查询(或使用查询生成器)中为表起别名?

如何在查询中为 eloquent 模型起别名

如何在laravel eloquent中为左连接表起别名

如何在 MySQL 中为数据库起别名?

在 Django QuerySet.values 调用中为 dict 键起别名

11 MyBatis——别名设置