Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikibooksThe Free Textbook Project
Search

C# Programming/Variables

From Wikibooks, open books for an open world
<C Sharp Programming
Thelatest reviewed version waschecked on11 May 2022. There aretemplate/file changes awaiting review.
C# Programming
Cover |Introduction |Basics |Classes |Advanced Topics |The .NET Framework |Index

Variables are used to store values. More technically, a variablebinds anobject (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:

stringname="Dr. Jones";Console.WriteLine("Good morning "+name);

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 explicittype. 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 typestring. This is a legal statement. However, if we had saidintname ="Dr. Jones", the compiler would have thrown an error telling us that you cannot implicitly convert betweenint andstring. There are methods for doing this, but we will talk about them later.

Fields, local variables, and parameters

[edit |edit source]

C# supports several program elements corresponding to the general programming concept ofvariable:fields,parameters, andlocal variables.

Fields

[edit |edit source]

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

Each field has a visibility ofpublic,protected,internal,protected internal, orprivate (from most visible to least visible).

Local variables

[edit |edit source]

Like fields, local variables can optionally beconstant (const). 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

[edit |edit source]

Parameters are variables associated with a method.

Anin 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++.

Anout 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 beunbound upon method entry, thus it is illegal to reference anout parameter before assigning it a value. It alsomust be assigned by the method in each valid (non-exceptional) code path through the method in order for the method to compile.

Areference parameter is similar to anout parameter, except that it isbound before the method call and it need not be assigned by the method.

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

// Each pair of lines is what the definition of a method and a call of a//   method with each of the parameters types would look like.// In param:voidMethodOne(intparam1)// definitionMethodOne(variable);// call// Out param:voidMethodTwo(outstringmessage)// definitionMethodTwo(outvariable);// call// Reference param;voidMethodThree(refintsomeFlag)// definitionMethodThree(reftheFlag)// call// ParamsvoidMethodFour(paramsstring[]names)// definitionMethodFour("Matthew","Mark","Luke","John");// call

Types

[edit |edit source]

Eachtype in C# is either avalue type or areference 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

[edit |edit source]

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 beboxed (wrapped inside an object), allowing their values to be used like objects.

Reference types

[edit |edit source]

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

[edit |edit source]

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:

// C#publicvoidUsingCSharpTypeAlias(){inti=42;}publicvoidEquivalentCodeWithoutAlias(){System.Int32i=42;}
' Visual Basic .NETPublicSubUsingVisualBasicTypeAlias()DimiAsInteger=42EndSubPublicSubEquivalentCodeWithoutAlias()DimiAsSystem.Int32=42EndSub

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 eachvalue type a consistent size across platforms and compilers. That consistency is an important distinction from other languages such as C, where, e.g. along is only guaranteed to be atleast as large as anint, and is implemented with different sizes by different compilers. Asreference types, variables of types derived fromobject (i.e. anyclass) are exempt from the consistent size requirement. That is, the size ofreference types likeSystem.IntPtr, as opposed tovalue types likeSystem.Int32, may vary by platform. Fortunately, there is rarely a need to know the actual size of areference type.

There are two predefinedreference types:object, an alias for theSystem.Object class, from which all other reference types derive; andstring, an alias for theSystem.String class. C# likewise has several integral value types, each an alias to a corresponding value type in theSystem 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'sSystem.Int32 type implements aToString() method to convert the value of an integer to its string representation, C#'sint type exposes that method:

inti=97;strings=i.ToString();// The value of s is now the string "97".

Likewise, theSystem.Int32 type implements theParse() method, which can therefore be accessed via C#'sint type:

strings="97";inti=int.Parse(s);// The value of i is now the integer 97.

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

objectboxedInteger=97;intunboxedInteger=(int)boxedInteger;

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.

objectgetInteger="97";intanInteger=(int)getInteger;// No compile-time error. The program will crash, however.

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

Integers

[edit |edit source]
C# Alias.NET TypeSize (bits)Range
sbyteSystem.SByte8-128 to 127
byteSystem.Byte80 to 255
shortSystem.Int1616-32,768 to 32,767
ushortSystem.UInt16160 to 65,535
charSystem.Char16A unicode character of code 0 to 65,535
intSystem.Int3232-2,147,483,648 to 2,147,483,647
uintSystem.UInt32320 to 4,294,967,295
longSystem.Int6464-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ulongSystem.UInt64640 to 18,446,744,073,709,551,615

Floating-point

[edit |edit source]
C# Alias.NET TypeSize (bits)PrecisionRange
floatSystem.Single327 digits1.5 x 10-45 to 3.4 x 1038
doubleSystem.Double6415-16 digits5.0 x 10-324 to 1.7 x 10308
decimalSystem.Decimal12828-29 decimal places1.0 x 10-28 to 7.9 x 1028

Other predefined types

[edit |edit source]
C# Alias.NET TypeSize (bits)Range
boolSystem.Boolean32true or false, which aren't related to any integer in C#.
objectSystem.Object32/64Platform dependent (a pointer to an object).
stringSystem.String16*lengthA unicode string with no special upper bound.

Custom types

[edit |edit source]

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

Customvalue types are declared with thestruct orenum keyword. Likewise,custom reference types are declared with theclass keyword.

Arrays

[edit |edit source]

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

string[]a_str;

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

a_str=newstring[5];

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

string[]a_str=newstring[5];

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:

staticvoidswap(int[]a_iArray,intiI,intiJ){intiTemp=a_iArray[iI];a_iArray[iI]=a_iArray[iJ];a_iArray[iJ]=iTemp;}

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

ushort[]a_usNumbers=newushort[234];[...]for(ushortus=0;us<a_usNumbers.Length;us++){a_usNumbers[us]=us;}

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

Text & variable example

[edit |edit source]
usingSystem;namespaceLogin{classUsername_Password{publicstaticvoidMain(){stringusername,password;Console.Write("Enter username: ");username=Console.ReadLine();Console.Write("Enter password: ");password=Console.ReadLine();if(username=="SomePerson"&&password=="SomePassword"){Console.WriteLine("Access Granted.");}elseif(username!="SomePerson"&&password=="SomePassword"){Console.WriteLine("The username is wrong.");}elseif(username=="SomePerson"&&password!="SomePassword"){Console.WriteLine("The password is wrong.");}else{Console.WriteLine("Access Denied.");}}}}

Conversion

[edit |edit source]

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

[edit |edit source]

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 beimplicit (i.e. an explicitcast is not required).

Inheritance polymorphism

[edit |edit source]

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

[edit |edit source]

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.

Retrieved from "https://en.wikibooks.org/w/index.php?title=C_Sharp_Programming/Variables&oldid=4057504"
Category:

[8]ページ先頭

©2009-2025 Movatter.jp