Why is C # not using "aliases" by default?

Consider the following code.

using System.ComponentModel.DataAnnotations;

namespace Foo
{
    public class Bar
    {
        [Required, MaxLength(250)]
        public virtual string Name { get; set; }
    }
}

      

Unless you have a fancy IDE (which looks for all sorts of search and static analysis behind the scenes), this is pretty ambiguous as to where "Required" and "MaxLength" actually come from. Especially if several impotence can be imported with a similar value.

As a relative newbie to C #, I find myself always having a hard time figuring out where certain things are coming from. Especially when looking at other code snippets in places like StackOverflow.

using DataAnnotations = System.ComponentModel.DataAnnotations;

namespace Foo
{
    public class Bar
    {
        [DataAnnotations.Required, DataAnnotations.MaxLength(250)]
        public virtual string Name { get; set; }
    }
}

      

Now it is very obvious where "Required" and "MaxLength" come from. You can take it a step further and do something like:

using Required = System.ComponentModel.DataAnnotations.RequiredAttribute;
using MaxLength = System.ComponentModel.DataAnnotations.MaxLengthAttribute;

namespace Foo
{
    public class Bar
    {
        [Required, MaxLength(250)]
        public virtual string Name { get; set; }
    }
}

      

Now this is very similar to how PHP and Js ES6 work.

I am curious why this is not the default for C #? And why pretty much every other C # dev I've talked to considers an alias of bad practice? Perhaps there is some underlying reason for performance?

+3


source to share


1 answer


Why does it matter where the types / definitions come from?

If you are really concerned about what namespace is present in Visual Studio, there are several ways to find out, which are my favorites below:

  • Hover over the type /. ... This often shows the fully qualified name of the type. (Hovering new SomeType()

    shows the method name that is applied to the attributes.)
  • Press F12 / Go To Definition. Even if you don't have a source to define, using F12or Right ClickGo To Definitionwill take you to a metadata file that shows you all public members of that type. It does not work with keywords ( out

    , ref

    , return

    , null

    etc.), but it works with basic pseudonyms ( int

    , string

    etc.), and traditional types ( enum

    , interface

    , class

    , struct

    etc.). This includes the namespace, type-name, and all public API members. If there are XML documents, they are also included. If youF12extension method, you are taken to the class metadata for that extension method. This is very useful for determining where a method came from if you feel like it was being introduced as something it shouldn't be.

So now it's not that hard to figure out which namespace this type came from. So what about aliases using

when you really need them?

Real life scenario: I was working on a Windows Forms Model for the XNA Framework. XNA Framework is of type Color

and my structure is of type Color

. Now I often use both of these namespaces together, but I only need one of the types Color

to be used initially. Often times I have a list of operators using

that include something like:

using XnaColor = Microsoft.Xna.Framework.Color;
using Color = Evbpc.Framework.Drawing.Color;

      

Thus, it removes the problem of ambiguity.

Why are there no using

default aliases?

Probably because they are almost never needed. We really don't need them. If you are concerned that the namespace that such a type comes from is much easier to do a quick lookup than for an alias all and force the namespace that needs to be defined. With this speed you can like-thread bar using

statements completely and completely qualify everything.

The biggest use of two cases that I have had ever an alias using

:

  • Eliminate ambiguity between types. See example above.
  • Eliminate ambiguity between namespaces. Same as above, but I mean the whole namespace if many types are duplicated.

    using XnaF = Microsoft.Xna.Framework;
    using Evbpc.Framework.Drawing;
    
          

If you create code with Visual Studio, import types, etc., it will not use an alias. Visual Studio, instead, fully qualifies the name as needed. Do you ever right click and get A.B.Type

as the only option instead using A.B

? Good thing is usually a good place for a nickname.

I warn you though aliases using

seem to increase maintainability requirements. (It may not have backups, but I won't lie - this project that I have multiple aliases makes me forget what / what I used to call the alias.)

In general, in my experience, if you need to use an alias using

, you are probably breaking the rule somewhere.



Why don't we use them on a regular basis?

Because they suck. They make the code harder to read (take your example DataAnnotations.MaxLength

, why do I need to read it? I don't care what MaxLength

's in System.ComponentModel.DataAnnotations

, I don't care if it's set correctly), they disorganize the code (now I forcefully remember that the attribute is in System.ComponentModel.DataAnnotations

instead of System.ComponentModel.DataAnnotations.Schema

), and they're just generally clumsy.

Take your previous example, I have an Entity Framework project that has attributes in a class like this:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Key, Column(Order = 2)]
[MaxLength(128)]
public string UserId { get; set; }

[ForeignKey(nameof(UserId))]
public virtual ApplicationUser User { get; set; }

      

Now with your example, I will have one of the following:

using DataAnnotations = System.ComponentModel.DataAnnotations;

[DataAnnotations.Key, DataAnnotations.Schema.Column(Order = 2)]
[DataAnnotations.MaxLength(128)]
public string UserId { get; set; }

[DataAnnotations.Schema.ForeignKey(nameof(UserId))]
public virtual ApplicationUser User { get; set; }

      

Or:

using DataAnnotations = System.ComponentModel.DataAnnotations;
using Schema = System.ComponentModel.DataAnnotations.Schema;

[DataAnnotations.Key, Schema.Column(Order = 2)]
[DataAnnotations.MaxLength(128)]
public string UserId { get; set; }

[Schema.ForeignKey(nameof(UserId))]
public virtual ApplicationUser User { get; set; }

      

Or even worse:

using KeyAttribute = System.ComponentModel.DataAnnotations.KeyAttribute;
using MaxLengthAttribute = System.ComponentModel.DataAnnotations.MaxLengthAttribute;
using ColumnAttribute = System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
using ForeignKeyAttribute = System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute;

[Key, Column(Order = 2)]
[MaxLength(128)]
public string UserId { get; set; }

[ForeignKey(nameof(UserId))]
public virtual ApplicationUser User { get; set; }

      

Sorry, but this is just awful. This is why “everyone” you talk to avoids them and thinks it's a bad idea. I'm just sticking to sane [1] importing namespaces and dealing with the very minute potential that causes conflicts. Then I will use an alias.

If you really can't find what namespace the type is in (let's say you're pulling code from Stack Overflow), click up on MSDN , go to Library and look for the type. (Ie, look for KeyAttribute

or MaxLengthAttribute

and the first links are API links.)

[1]: intelligently I mean to do it with responsibility and care. Don't just blindly import / use namespaces, try to restrict them as much as possible. SRP and polymorphism usually allow us to keep the list using

fairly small in each file.

+7


source







All Articles