开发者

Why can't a class member's name be the same as one of its nested classes?

开发者 https://www.devze.com 2023-02-05 04:37 出处:网络
Or why is the following impossible: class Material { class Keys { ... } Material.Keys Keys { get; set; } // Illegal

Or why is the following impossible:

class Material
{
    class Keys
    {
        ...
    }

    Material.Keys Keys { get; set; } // Illegal
}

I don't see any possible ambiguity. When accessed by instance, return the property. When access statically, return the class. Or am I missing something?

I'm not asking for a "fix" (I know I co开发者_JAVA技巧uld just name it differently, like MaterialKeys or the like), but more of a technical reason behind this limit.


But imagine you had this:

class Material
{
    class Keys
    {
        ...
    }

    static Material.Keys Keys = new Keys();
}

Now both are at "static" scope. Now, can the compiler disambiguate in all cases? If not, then this can't be allowed.

I suppose it's possible that the disambiguation would work for static fields/properties/methods, and not for instance members. Or the other way around. If that were the case, would you want the language specification to allow an instance member to have the same name as an internal class, but disallow it for statics? That would just be confusing.

But then, having a member match the name of an internal class is pretty confusing anyway.


"Anything that's not ambiguous should be legal" is absolutely NOT a design principle of the C# language. The C# language is designed to be a "pit of quality" language; that is, the rules of the language should throw you into a pit full of clearly correct code, and you have to work to climb out of the pit to turn it into incorrect code. The idea that "whatever is not ambiguous should be legal" works in most cases directly against the concept of a "pit of quality" language.

Furthermore, your idea that I need to provide you a justification for not doing a feature is backwards. We don't ever need to provide justification for not doing a feature. Rather, proposed features must be justified by demonstrating that their benefits outweigh their enormous costs. Features are very expensive and we have a limited budget; we must only do the very best features to yield their benefits to our customers.

Your proposed feature enables the easy production of code that is brittle and confusing; it helps make C# into a "pit of despair" language instead of a "pit of quality" language. Features which add brittleness and confusion to the language must add an enormous benefit to compensate for those costs. What is in your opinion the enormous benefit that this feature adds to the language that justifies its costs?

If the answer is "there is no such benefit" then now you know why the language doesn't have that feature: because it makes the language worse, net.

If there is a benefit, I'm happy to consider its merits for hypothetical future versions of the language.


You said,

When accessed by instance, return the property. When access statically, return the class.

But what if you say just Keys somewhere inside Material? Is this a static or instance access? Does this refer to the property Keys or the nested type Keys? It is actually ambiguous.

For example,

class Material
{
    class Keys
    {
        public static int Length;
    }

    string Keys { get; set; }

    public void Process()
    {
        // Does this refer to string.Length (via property Keys)
        // or Material.Keys.Length? It actually refers to both.
        Console.WriteLine(Keys.Length);
    }
}

As pointed out in the comments, this is not the whole story; but almost. It is valid to have a property named Color of the type Color and there is no clash:

public Color Color { get; set; }

Color.FromName(...)   // refers to static method on the type ‘Color’
Color.ToString()      // refers to instance method on the property’s value

But this is easy to resolve simply because things in the current scope win over things in more outer scopes:

public class MyType { public string FromName(string name) { return null; } }
public MyType Color;

Color.FromName(...)   // unambiguously refers to MyType::FromName(string)
                      // via the property Color

Not so easy in your example — the nested class Keys and the property Keys are in the same scope (have the same declaring type). How do you decide which to give priority? And even if you did decide to give one of them priority, this would be only marginally useful because you could still only have two things of the same name, and one would have to be static and the other instance.


My answer approaches the question from a slightly different perspective, compared to the other questions. Of the following two statements in a C# language specification:

The same identifier may not be used in different definitions within one scope

and

The same identifier may not be used in different definitions within one scope, unless it is probably impossible for any ambiguity to arise when the identifier is used

, the first is much simpler.

Simplicity is a key goal in language design, because simpler languages are easier for compiler and interpreter authors to implement, easier for tools to generate and manipulate, easier for beginners to learn, and easier for programmers to understand. When considering any language feature, the complexity that that feature adds to the language should be considered as a negative, and must therefore be balanced by an at least equal measure of usefulness. As you stated yourself, allowing this would add no real functionality (as it is so easy to work around), so there was no compelling reason to further complicate the C# spec by including it.


Because the nested class Keys is a member of Material as is the property Keys. You've got two members called Keys.

In the same way you can't have two properties called the same thing:

public class Bar
{
    private bool Foo { get; set; }
    private string Foo { get; set; }
}

When you access Foo which one are you trying to access?

public class Material : Keys
{

    private Keys K { get; set; }
}

public class Keys
{

}

Works fine, but is probably not what you're after.

0

精彩评论

暂无评论...
验证码 换一张
取 消