The path to LINQ 2: C #3.0 language functions (I)

Source: Internet
Author: User

In the previous section of LINQ, we have seen the implicit type variables var, extension method, and lambda expressions. That's right. They are the cornerstone of the LINQ technology. They make the implementation of LINQ possible and simplify the writing of the LINQ expression. In this article, I will discuss the language functions of C #3.0, including implicit local variables, automatic attributes, and anonymous types.

 

Implicit local variables

C # is a strongly typed language, which means that we must specify the specific type of the variable when declaring the variable, for example:

        static void DeclareExplicitVars()
{
int myInt = 0;
bool myBool = true;
string myString = "Hello, World!";
}

Now C #3.0 provides us with a new keyword var. You can use it to replace the formal data type name (such as int, bool, string ). When the var keyword is used, the compiler will deduce the Data Type of the variable based on the initial value used to initialize the local variable. For example, the preceding variable declaration can be changed to the following code:

Static void DeclareImplicitVars ()
{
// Declaration method of implicit local variables: var varName = defaultValue;
Var myInt = 0;
Var myBool = true;
Var myString = "Hello, World! ";
}

The above two methods are equivalent. The compiler can infer that the myInt type is System. Int32 based on the initial value, the myBool type is System. Boolean, And the myString type is System. String.

In addition, we can use implicit types for all types in the base class library, including arrays, generics, and custom types.

        public   static void   DeclareImplicitVars()
{
// declare implicit variables
var numbers = new int[] { 2, 4, 6, 8 };
var persons = new List<Person>();
var car = new SportsCar();

// verify the data type using reflection
Console.WriteLine("numbers is a: {0}", numbers.GetType().Name);
Console.WriteLine("persons is a: {0}", persons.GetType().Name);
Console.WriteLine("car is a: {0}", car.GetType().Name);
}

The output result is as follows:

Var In foreach Statement

In the foreach loop statement, we can also use the implicit type. As you expected, the compiler will infer the correct data type:

        static   void VarInForeachLoop()
{
var numbers = new int[] { 2, 4, 6, 8 };
foreach (var item in numbers)
{
Console.WriteLine("Item value: {0}", item);
}
}
Limitations on implicit type variables

Note that there are multiple restrictions when using the var keyword. First, the implicit type can only be applied to the declaration of local variables in the method or attribute. var cannot be used to define the return value, parameter type, or type of data members.

Second, the local variables declared using var must be assigned an initial value and cannot use null as the initial value. The reason is that the compiler must be able to deduce the actual type of the variable based on the initial value.

Implicit data is strongly typed.

Implicit local variables generate strongly typed data. Therefore, the var keyword is different from the Variant Data Type of the script language (such as VBScript or Perl). For the latter, a variable can save different types of values in its lifecycle.

In fact, type inference maintains the strong type feature of C # language and only affects variable declaration during compilation. After initialization, the compiler has deduced the exact data type for the implicit type variable. If different types of values are assigned to variables, compilation errors may occur:

Static void ImplicitTypingStrongTyping ()
{
// The Compiler knows that s is of the System. String type.
Var s = "This variable can only hold string data! ";
S = "It's OK .";

// Call any basic method
String upper = s. ToUpper ();

// Error! Data of the numeric type cannot be assigned to a variable of the String type.
S = 100;
}
Functions of implicit local variables

After reading the above introduction, you will surely wonder what the use of this structure is. If it is just for simplicity, it is not worth it, because doing so may make other people who read the code confused. However, when we use LINQ, the advantages of the var keyword are apparent. It can dynamically create a result set based on the Query format, so that we do not need to display and define the types that may be returned by the query. In many cases, we cannot see the return types of LINQ at a glance. For example:

        public   static void   QueryOverInts()
{
int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 5 };
var subset = from i in numbers where i < 10 select i;

Console.Write("values in subset: ");
foreach (var i in subset)
Console.Write("{0} ", i);
Console.WriteLine();

Console.WriteLine("subset is a: {0}", subset.GetType().Name);
Console.WriteLine("subset is defined in: {0}", subset.GetType().Namespace);
}

Output:

In fact, we can think that the var keyword is used only when defining the data returned from the LINQ query.

 

Automatic attributes

We know that the. NET language recommends using type attributes to encapsulate private data fields, rather than using the GetXXX () and SetXXX () methods. Because. NET base class libraries always use type attributes instead of traditional access and modification methods, you can use attributes to achieve better integration with. NET platforms. At the underlying layer, the C # attribute is mapped to the get _ and set _ prefixes. If the Name attribute is defined, C # automatically generates get_Name () and set_Name.

Consider the following C # type definition:

    class Person
{
private string firstName = string.Empty;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

private string lastName = string.Empty;
public string LastName
{
get { return lastName; }
set { lastName = value; }
}

private int level = 0;
public int Level
{
get { return level; }
set { level = value; }
}
}

Although it is not difficult to define attributes, if the attributes are only values and return values, it is also difficult to define the fields and attributes, especially in the case of many class attributes. C #3.0 provides an automatic attribute syntax to simplify the process of encapsulating data fields. Now, the above Person can be defined as follows:

    class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Level { get; set; }
}

When defining automatic attributes, you only need to specify the access modifier, data type, attribute name, and empty get/set scope. During compilation, the automatically generated private supported fields and the correct implementation of the get/set logic are used.

Note that,When defining automatic attributes, you must also provideGetAnd setKeywordsTherefore, you cannot define read-only or write-only automatic attributes.

 

Anonymous type

As an object-oriented programmer, we know how to define classes to express a given programming entity. When I need a type to be reused between projects, we usually create a C # class to provide the class with a series of required attributes, methods, and events. However, sometimes we may need to define classes to encapsulate some relevant data without any associated methods or events. In addition, classes do not need to be reused between projects. Even so, we still need to define a "temporary" class. Although the work is not very complicated, if we need to define a class to encapsulate many data members, it will consume a lot of time. I don't think everyone will want to turn programming into a mechanical movement.

The anonymous type provided by C #3.0 is generated for the above tasks. The anonymous type is a natural extension of the anonymous method, which can help us easily complete the above work.

When defining an anonymous type, use the New Keyword var and the object initialization syntax described earlier, as shown in the following example:

Static void TestAnonymousType ()
{
// Construct an anonymous object to indicate an employee
Var worker = new {FirstName = "Vincent", LastName = "Ke", Level = 2 };

// Display and Output
Console. WriteLine ("Name: {0}, Level: {1}", worker. FirstName + "" + worker. LastName, worker. Level );
}

When the code above is used to construct an anonymous object, the C # compiler automatically generates a class with a unique name during compilation. Because the class name is invisible in C #, you must use the var keyword to use implicit typing. In addition, we need to define a series of attributes through the object initialization syntax to encapsulate each data.

Anonymous internal representation

All anonymous types are automatically inherited from System. Object. We can call methods such as ToString (), GetHashCode (), Equals (), and GetType () on the worker of implicit type.

You can define the following method to view anonymous information:

Static void ReflectAnonymousType (object obj)
{
Console. WriteLine ("Type Name: {0}", obj. GetType (). Name );
Console. WriteLine ("Base Class: {0}", obj. GetType (). BaseType );
Console. WriteLine ("obj. ToString () = {0}", obj. ToString ());
Console. WriteLine ("obj. GetHashCode () = {0}", obj. GetHashCode ());
}

Static void TestAnonymousType ()
{
// Construct an anonymous object to indicate an employee
Var worker = new {FirstName = "Vincent", LastName = "Ke", Level = 2 };
ReflectAnonymousType (worker );
}

The result is as follows:

In the preceding example, the worker type is <> f _ anonymoustype0' 3 (different versions may be used). The type name of the anonymous type is determined by the compiler. More importantly, each name/value pair defined by the object initialization syntax is mapped to read-only attributes with the same name and encapsulated private data members.

Method ToString () And GetHashCode () Implementation

As you can see above, the anonymous type is directly System. Object, and the Equals (), GetHashCode (), and ToString () methods are overwritten. ToString () generates and returns a string based on each name/value pair, as shown in.

The implementation of GetHashCode () uses each anonymous member variable to calculate the hash value. If two anonymous types have the same gender and are assigned the same value, the same hash value is generated, the anonymous type can work well with the Hashtable container.

Equality semantics of anonymous types

The value-based semantics is used by the compiler to determine the object, but the compiler does not overload (= and! =) Equal operator, so when using = to compare two anonymous objects, it is based on the reference Semantics !" = "The comparison reference is the default action for all classes. For example:

Static void AnonymousTypeEqualityTest ()
{
// Construct two anonymous types with the same name/value pair
Var worker1 = new {FirstName = "Harry", SecondName = "Folwer", Level = 2 };
Var worker2 = new {FirstName = "Harry", SecondName = "Folwer", Level = 2 };

// Equals Test
If (worker1.Equals (worker2 ))
Console. WriteLine ("worker1 equals worker2 ");
Else
Console. WriteLine ("worker1 not equals worker2 ");

// = Test
If (worker1 = worker2)
Console. WriteLine ("worker1 = worker2 ");
Else
Console. WriteLine ("worker1! = Worker2 ");

// Type Name Test
If (worker1.GetType (). Name = worker2.GetType (). Name)
Console. WriteLine ("we are both the same type ");
Else
Console. WriteLine ("we are different types ");
}

Result:

 

Blog series Navigation:

Blog navigation of the road to LINQ

Road 1 of LINQ: Introduction to LINQ

The path to LINQ 2: C #3.0 language functions (I)

The path to LINQ 3: C #3.0 language functions (II)

The road to LINQ 4: the syntax of the LINQ Method

The path to LINQ 5: a linq query expression

6: latency in Execution (Deferred Execution)

7: subquery, creation policy, and Data Conversion

8: Explain query (Interpreted Queries)

Road 9: LINQ to SQL and Entity Framework (I)

10: The Path to LINQ to SQL and Entity Framework (below)

11: Filtering by LINQ Operators)

12: Data Conversion (Projecting) of LINQ Operators)

Connection to the LINQ road 13: connection to the LINQ Operators (Joining)

The road to LINQ 14: sorting and Grouping of LINQ Operators (Ordering and Grouping)

Road 15 to LINQ: Element Operators, set methods, and quantifiers of LINQ Operators

LINQ LINQ 16: Collection Operators, Zip Operators, conversion methods, and generator methods of LINQ Operators

X-DOM introduction to the road to LINQ 17: LINQ to XML;

18: navigation and query of LINQ to XML

Road 19: X-DOM update and interaction with Value attributes for LINQ to XML

Path 20 to LINQ to XML: Documents, Declarations, and Namespaces

The path to LINQ 21: The X-DOM for the generation of LINQ to XML (Projecting)

Post of the series of blogs on the road to LINQ

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.