C Sharp Programming/Variables

Variables are used to store values. More technically, a variable binds an object (in the general sense of the term, i.e. a specific value) to an identifier (the variable's name) so that the object can be accessed later. Variables can, for example, store a value for later use:

In this example "name" is the identifier and "Dr. Jones" is the value that we bound to it. Also, each variable is declared with an explicit type. Only values whose types are compatible with the variable's declared type can be bound to (stored in) the variable. In the above example we stored "Dr. Jones" into a variable of the type. This is a legal statement. However, if we had said =, the compiler would have thrown an error telling us that you cannot implicitly convert between  and. There are methods for doing this, but we will talk about them later.

Fields, local variables, and parameters
C# supports several program elements corresponding to the general programming concept of variable: fields, parameters, and local variables.

Fields
Fields, sometimes called class-level variables, are variables associated with classes or structures. An instance variable is a field associated with an instance of the class or structure, while a static variable, declared with the keyword, is a field associated with the type itself. Fields can also be associated with their class by making them constants, which requires a declaration assignment of a constant value and prevents subsequent changes to the field.

Each field has a visibility of public, protected, internal, protected internal, or private (from most visible to least visible).

Local variables
Like fields, local variables can optionally be constant. Constant local variables are stored in the assembly data region, while non-constant local variables are stored on (or referenced from) the stack. They thus have both a scope and an extent of the method or statement block that declares them.

Parameter
Parameters are variables associated with a method.

An in parameter may either have its value passed in from the caller to the method's environment, so that changes to the parameter by the method do not affect the value of the caller's variable, or passed in by reference, so that changes to the variables will affect the value of the caller's variable. Value types (int, double, string) are passed in "by value" while reference types (objects) are passed in "by reference." Since this is the default for the C# compiler, it is not necessary to use '&', as in C or C++.

An out parameter does not have its value copied, thus changes to the variable's value within the method's environment directly affect the value from the caller's environment. Such a variable is considered by the compiler to be unbound upon method entry, thus it is illegal to reference an out parameter before assigning it a value. It also must be assigned by the method in each valid (non-exceptional) code path through the method in order for the method to compile.

A reference parameter is similar to an out parameter, except that it is bound before the method call and it need not be assigned by the method.

A params parameter represents a variable number of parameters. If a method signature includes one, the params argument must be the last argument in the signature.

Types
Each type in C# is either a value type or a reference type. C# has several predefined ("built-in") types and allows for declaration of custom value types and reference types.

There is a fundamental difference between value types and reference types: Value types are allocated on the stack, whereas reference types are allocated on the heap.

Value types
The value types in the .NET framework are usually small, frequently used types. The benefit of using them is that the type requires very little resources to get up and running by the CLR. Value types do not require memory to be allocated on the heap and therefore will not cause garbage collection. However, in order to be useful, the value types (or types derived from it) should remain small - ideally below 16 bytes of data. If you choose to make your value type bigger, it is recommended that you do not pass it to methods (which can require a copy of all its fields), or return it from methods.

Although this sounds like a useful type to have, it does have some flaws, which need to be understood when using it.


 * Value types are always copied (intrinsically) before being passed to a method. Changes to this new object will not be reflected back in the original object passed into the method.
 * Value types do not /need/ you to call their constructor. They are automatically initialized.
 * Value types always initialize their fields to 0 or null.
 * Value types can NEVER be assigned a value of null (but can using Nullable types)
 * Value types sometimes need to be boxed (wrapped inside an object), allowing their values to be used like objects.

Reference types
Reference types are managed very differently by the CLR. All reference types consist of two parts: A pointer to the heap (which contains the object), and the object itself. Reference types are slightly heavier weight because of the management behind the scenes needed to keep track of them. However, this is a minor price to pay for the flexibility and speed gains from passing a pointer around, rather than copying values to/from methods.

When an object is initialized, by use of the constructor, and is of a reference type, the CLR must perform four operations:


 * 1) The CLR calculates the amount of memory required to hold the object on the heap.
 * 2) The CLR inserts the data into the newly created memory space.
 * 3) The CLR marks where the end of the space lies, so that the next object can be placed there.
 * 4) The CLR returns a reference to the newly created space.

This occurs every single time an object is created. However the assumption is that there is infinite memory, therefore some maintenance needs to take place - and that's where the garbage collector comes in.

Integral types
Because the type system in C# is unified with other languages that are CLI-compliant, each integral C# type is actually an alias for a corresponding type in the .NET framework. Although the names of the aliases vary between .NET languages, the underlying types in the .NET framework remain the same. Thus, objects created in assemblies written in other languages of the .NET Framework can be bound to C# variables of any type to which the value can be converted, per the conversion rules below. The following illustrates the cross-language compatibility of types by comparing C# code with the equivalent Visual Basic .NET code:

Using the language-specific type aliases is often considered more readable than using the fully-qualified .NET Framework type names.

The fact that each C# type corresponds to a type in the unified type system gives each value type a consistent size across platforms and compilers. That consistency is an important distinction from other languages such as C, where, e.g. a is only guaranteed to be at least as large as an , and is implemented with different sizes by different compilers. As reference types, variables of types derived from (i.e. any ) are exempt from the consistent size requirement. That is, the size of reference types like, as opposed to value types like , may vary by platform. Fortunately, there is rarely a need to know the actual size of a reference type.

There are two predefined reference types:, an alias for the class, from which all other reference types derive; and , an alias for the  class. C# likewise has several integral value types, each an alias to a corresponding value type in the namespace of the .NET Framework. The predefined C# type aliases expose the methods of the underlying .NET Framework types. For example, since the .NET Framework's type implements a  method to convert the value of an integer to its string representation, C#'s  type exposes that method:

Likewise, the type implements the  method, which can therefore be accessed via C#'s  type:

The unified type system is enhanced by the ability to convert value types to reference types (boxing) and likewise to convert certain reference types to their corresponding value types (unboxing). This is also known as casting.

Boxing and casting are, however, not type-safe: the compiler won't generate an error if the programmer mixes up the types. In the following short example the mistake is quite obvious, but in complex programs it may be very difficult to spot. Avoid boxing, if possible.

The built-in C# type aliases and their equivalent .NET Framework types follow:

Custom types
The predefined types can be aggregated and extended into custom types.

Custom value types are declared with the or  keyword. Likewise, custom reference types are declared with the keyword.

Arrays
Although the number of dimensions is included in array declarations, the size of each dimension is not:

Assignments to an array variable (prior to the variable's usage), however, specify the size of each dimension:

As with other variable types, the declaration and the initialization can be combined:

It is also important to note that like in Java, arrays are passed by reference, and not passed by value. For example, the following code snippet successfully swaps two elements in an integer array:

It is possible to determine the array size during runtime. The following example assigns the loop counter to the unsigned short array elements:

Since C# 2.0, it is possible to have arrays also inside of structures.

Conversion
Values of a given type may or may not be explicitly or implicitly convertible to other types depending on predefined conversion rules, inheritance structure, and explicit cast definitions.

Predefined conversions
Many predefined value types have predefined conversions to other predefined value types. If the type conversion is guaranteed not to lose information, the conversion can be implicit (i.e. an explicit cast is not required).

Inheritance polymorphism
A value can be implicitly converted to any class from which it inherits or interface that it implements. To convert a base class to a class that inherits from it, the conversion must be explicit in order for the conversion statement to compile. Similarly, to convert an interface instance to a class that implements it, the conversion must be explicit in order for the conversion statement to compile. In either case, the runtime environment throws a conversion exception if the value to convert is not an instance of the target type or any of its derived types.

Scope and extent
The scope and extent of variables is based on their declaration. The scope of parameters and local variables corresponds to the declaring method or statement block, while the scope of fields is associated with the instance or class and is potentially further restricted by the field's access modifiers.

The extent of variables is determined by the runtime environment using implicit reference counting and a complex garbage collection algorithm.

C 샤프 프로그래밍/변수