Today, I ran into some code that goes like this.
namespace Foo
{
public enum Game{ High, Low};
public enum Switch{On, Off};
public class Bar()
{
// Blah
}
}
I could not figure out what the difference between that and declaring the enums inside the class was. AFAIK, you can still "override" those enums inside the class.
Enums are types, just like classes. When you declare an enum inside a class, it's just a nested type. A nested enum just hides other enums with the same name that are declared in outer scopes, but you can still refer to the hidden enum through its fully qualified name (using the namespace prefix, in your example).
The decision whether to declare a top level enum or a nested enum depends on your design and whether those enums will be used by anything other than the class. You can also make a nested enum private or protected to its enclosing type. But, top level enums are far more common.
If you put the enumerations in the class, you would need to specify the class name every time you use it outside of the class, for example:
SomeLongClassName x = new SomeLongClassName(SomeLongClassName.Game.High, SomeLongClassName.Switch.On);
instead of:
SomeLongClassName x = new SomeLongClassName(Game.High, Switch.On);
You could decide to put the ennumeration inside a class if it's used only by that class, but that kind of isolation only works for classes. If you have an enumeration that is only used by a single method, you can't put it inside the method.
Related
Right now, I am using "string" to enumerate a list of equipment slots on a character.
I am also using "string" to enumerate the class type that the item can be equipped on.
This makes all my methods where I get, remove, generate, etc. items involve having two string parameters that is an equipment slot and class type.
What I really would like is to use 2 classes so that I have 2 strongly typed concepts for the slot and class_type.
The problem is that string is a sealed class and thus I cannot extend it!
A solution I conceived is to use "using SlotType = string;" as alias but I don't know how to have this work GLOBALLY.
How do you define a global alias for a class?
In C# you can create a type alias using "using". Because obviously that term needed a 3rd meanings in C# ;) However 'the scope of a using directive is limited to the file in which it appears.', so it would not apply globally.
There is another option - create a subclass. For example,
public class ListOfIntegers : List<int>{
//Nothing to do here.
}
would give you a sort-off-alias for List<int> that applies everywhere ListOfIntegers is given as Project Reference.
As for not being able to extend something: Just encapsulate it instead.
public class TypedString1 {
public value;
}
public class TypedString2 {
public value;
}
But you may want to set it up so that string overloads are used for stuff like Equality and ToString calls. Also propably a implicit cast to string to make it easier to use.
The following is an interview question. I came up with a solution, but I'm not sure why it works.
Question:
Without modifying the Sparta class, write some code that makes MakeItReturnFalse return false.
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
My solution: (SPOILER)
public class Place
{
public interface Sparta { }
}
But why does Sparta in MakeItReturnFalse() refer to {namespace}.Place.Sparta instead of {namespace}.Sparta?
But why does Sparta in MakeItReturnFalse() refer to {namespace}.Place.Sparta instead of {namespace}.Sparta?
Basically, because that's what the name lookup rules say. In the C# 5 specification, the relevant naming rules are in section 3.8 ("Namespace and type names").
The first couple of bullets - truncated and annotated - read:
If the namespace-or-type-name is of the form I or of the form I<A1, ..., AK> [so K = 0 in our case]:
If K is zero and the namespace-or-type-name appears within a generic method declaration [nope, no generic methods]
Otherwise, if the namespace-or-type-name appears within a type declaration, then for each instance type T (Ā§10.3.1), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
If K is zero and the declaration of T includes a type parameter with name I, then the namespace-or-type-name refers to that type parameter. [Nope]
Otherwise, if the namespace-or-type-name appears within the body of the type declaration, and T or any of its base types contain a nested accessible type having name I and K type parameters, then the namespace-or-type-name refers to that type constructed with the given type arguments. [Bingo!]
If the previous steps were unsuccessful then, for each namespace N, starting with the namespace in which the namespace-or-type-name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
If K is zero and I is the name of a namespace in N, then... [Yes, that would succeed]
So that final bullet point is what picks up the Sparta class if the first bullet doesn't find anything... but when the base class Place defines an interface Sparta, it gets found before we consider the Sparta class.
Note that if you make the nested type Place.Sparta a class rather than an interface, it still compiles and returns false - but the compiler issues a warning because it knows that an instance of Sparta will never be an instance of the class Place.Sparta. Likewise if you keep Place.Sparta an interface but make the Sparta class sealed, you'll get a warning because no Sparta instance could ever implement the interface.
When resolving a name to its value the "closeness" of the definition is used to resolve ambiguities. Whatever definition is "closest" is the one that is chosen.
The interface Sparta is defined within a base class. The class Sparta is defined in the containing namespace. Things defined within a base class are "closer" than things defined in the same namespace.
Beautiful question! I'd like to add a slightly longer explanation for those who don't do C# on a daily basis... because the question is a good reminder of name resolution issues in general.
Take the original code, slightly modified in the following ways:
Let's print out the type names instead of comparing them as in the original expression (i.e. return this is Sparta).
Let's define the interface Athena in the Place superclass to illustrate interface name resolution.
Let's also print out the type name of this as it is bound in the Sparta class, just to make everything very clear.
The code looks like this:
public class Place {
public interface Athena { }
}
public class Sparta : Place
{
public void printTypeOfThis()
{
Console.WriteLine (this.GetType().Name);
}
public void printTypeOfSparta()
{
Console.WriteLine (typeof(Sparta));
}
public void printTypeOfAthena()
{
Console.WriteLine (typeof(Athena));
}
}
We now create a Sparta object and call the three methods.
public static void Main(string[] args)
{
Sparta s = new Sparta();
s.printTypeOfThis();
s.printTypeOfSparta();
s.printTypeOfAthena();
}
}
The output we get is:
Sparta
Athena
Place+Athena
However, if we modify the Place class and define the interface Sparta:
public class Place {
public interface Athena { }
public interface Sparta { }
}
then it is this Sparta -- the interface -- that will beĀ available first to the name lookup mechanism and the output of our code will change to:
Sparta
Place+Sparta
Place+Athena
So we have effectively messed up with the type comparison in the MakeItReturnFalse function definition just by defining the Sparta interface in the superclass, which is found first by the name resolution.
But why does C# chose to prioritize interfaces defined in the superclass in the name resolution? #JonSkeet knows! And if you read his answer you'll get the details of the name resolution protocol in C#.
This question already has answers here:
Class.Class vs Namespace.Class for top level general use class libraries?
(7 answers)
Closed 8 years ago.
I am considering these two scenarios:
class StructuralCase
{
class Structure
{
...
}
class Material
{
...
}
class Forces
{
...
}
}
and
namespace StructuralCase
{
class Structure
{
...
}
class Material
{
...
}
class Forces
{
...
}
}
The thing is that inside "StructuralCase" I won't be declaring any instance variables, e.g., it will function as a "parent" for the rest of classes.
This lead me to consider converting StructuralClass to a namespace. What do you think about that? Is there any hard rule?
What you have are two different things.
First scenario class example:
You have an internal class with 3 nested private classes
In your second scenario namespace example:
You have 3 internal independent classes with no nesting.
If the classes should only be used within StructuralCase use the first example, otherwise if the classes are independent and have no relationship then the namespace is the way forward.
Generally, you want to use a namespace, if only because it enables using statements - otherwise you have to refer to the class by all nested classes (except inside the parent class itself, of course). Thus in case 1, outside reference would have to say
StructuralCase.Structure s = ...
instead of
using StructuralCase;
// ...
Structure s = ...
Functionally the only real reason to make a nested class is
So that the nested type has access to nonpublic members of the parent type. If this is a concern over API surface, see instead internal
So that the subclass isn't accessible outside the parent class, such as a specific struct used for results of a specific query
So that the child class can share some Generic Parameters from the parent class, such as factory classes which need the same generic parameters
I would just use Namespace, because you don't all the overhead of a class.
A class has more structure, variables, and methods, and offers layers of inheritance, but if you don't need them, don't use Class.
I have a mainForm variable that is used nearly everywhere in my program. I'd like to be able to reference to this variable without having to type the name of the class that holds this variable (i.e. instead of Global._mainForm, I should be able to just type _mainForm to access this variable anywhere within the same namespace).
What is the best way to accomplish this?
Anytime I see a global anything I get worried, so I would reconsider how your program is architected. You can almost always get away without having a globally accessible object. Although there are legitimate reasons to have a globally accessible object, usually I try to stay away from them.
From the little information you've given, you might be able to use events to talk to the main window instead of directly accessing it.
If you do have real need for a globally accessible object then you could do something like this
Note: In the code below everything is static, conversely you could create a special static class that holds a reference to the instance of the class you're really interested in. But there is no way that I'm aware of to hold a global reference that is outside of all namespaces to an instance of an object.
using Bar = ProbablyAReallyBadIdeaToHaveAGlobalAnythingButHeyWhyNot.TestClass;
namespace ProbablyAReallyBadIdeaToHaveAGlobalAnythingButHeyWhyNot
{
public static class TestClass
{
public static int TestFoo { get; set; }
}
}
namespace Foo.SomeOtherNamespace
{
class MyClassThatDoesStuff
{
public void DoStuff()
{
Bar.TestFoo = 123;
}
}
}
You can't accomplish this in C#.
Namespaces are simply part of the type name of a class. Lexically, you can think of a namespace as containing only other namespaces and classes.
Classes may contain fields, functions, events, properties, nested classes, etc., but not nested namespaces.
Therefore there is no way to to define a symbol in a namespace outside of class that aliases or refers to a symbol contained in a specific class.
When resolving the reference to the variable name _mainForm, the only place that it does not require additional qualification is from within the scope of the class that it is defined in.
If you are in a namespace scope that is the same as as the class that defines _mainForm (and _mainForm is a static instance), then you only need access it by qualifying it with the class name. Otherwise you will require additional namespace qualification, or perhaps trickery with a using directive. But outside of the containing class, you will always require a qualification of some kind to access _mainForm.
See http://en.csharp-online.net/ECMA-334:_10.7_Scopes for excruciating detail.
The only way I can see, in C#, for every class in a namespace to be able to directly address the same variable is by defining the variable as static in a base class used by all other classes in the namespace. Since static variables can be addressed as local variables within the class (or classes inheriting from) they are defined in, the variable will be available without class qualifications.
Can't say it is a good idea, but that's not what you asked ...
I have an enum (let's say DemoEnum) and I want to parse a value to this enum. I am writing
DemoEnum value;
if(DemoEnum.TryParse("input", out value))
{
this.Value = value;
}
Now the resharper suggests me, to use the base class qualifier.
I just want to know what's the benefit of using the base class qualifier?
Generally, it is a good idea to use the most generic solution possible.
DemoEnum.TryParse("input", out value)
Is the same call as (you're just making the static call from an inherited class rather than the base class):
Enum.TryParse<DemoEnum>("input", out value)
Using the base class qualifier (Enum) instead of your specific enum (DemoEnum) would insulate you from possible side effects of changing DemoEnum in the future. The reality is that you're really only going to run into issues if you change DemoEnum to a class without changing the name.
This is generally a larger issue when using classes (and ReSharper will give the same guidance in those situations).
The TryParse() method is a static method defined in the Enum class. Since your enum inherits everything from the Enum class, it also "inherits" static members. It's not true inheritance, the static members are just visible from the class.
The other answers are wrong in that some special translation is being done for you. All you are doing is accessing the static member from a derived class since all static members are accessible through your enum. The type of the identifier that you are accessing the static method from has no bearing at all on what the generic parameters are, only what the compiler is able to infer from them (or you explicitly provide).
To illustrate my point, consider these two enums:
enum First { A, B }
enum Second { A, B }
First firstVar;
Second secondVar;
// note we're using the `First` name
First.TryParse("A", out firstVar); // valid, firstVar <= First.A
First.TryParse("B", out secondVar); // still valid, secondVar <= Second.B
// is equivalent to
Enum.TryParse<First>("A", out firstVar); // generic type is inferred from type of firstVar
Enum.TryParse<Second>("B", out secondVar); // generic type is inferred from type of secondVar
What ReSharper is telling you is that you should be accessing the static member from the class that defined actually the member. Why should you do this?
Consider what would happen if your derived type defined a static member with the same exact name. (it's not possible in this case with enums but applicable to classes in general) What would happen to your code then? Any code that accessed the static member through the derived class will take on the new value and you will probably get no new warning about it. This may or may not be desired behavior so ReSharper is preemptively warning you that you should use the actual class that defined it (the base).
Looks like Resharper is suggesting you use Enum.TryParse - http://msdn.microsoft.com/en-us/library/dd783499.aspx
I bet if you look at the IL... DemoEnum.TryParse is just doing a base.TryParse
When you write DemoEnum.TryParse, the compiler transforms it to Enum.TryParse<DemoEnum>. There is no functional difference, and you don't really need to be insulated from possible side effects because you can't define methods in an enum type, so TryParse can't be redefined. My best guess is that it's a style preference.