[LINQ] Chapter 1 uses anonymous types

Posted by freshneco on Mon, 22 Nov 2021 08:03:26 +0100

Anonymous types use the keyword var. In short, anonymous type means that you don't have to specify a specific type. Just write VaR, and CSharp will calculate the data type defined by the expression on the right. The CSharp compiler then specifies that the defined variable is of that type. When a type is specified, it is equivalent to a strong type, and the compiler checks the type at run time.

Please note that you do not need to write type definitions because CSharp will help you calculate them. This is important because in a query language, any specific type you request and get is defined according to the context (query result). Simply put, the query result may return a type that has not been defined before.

1. Some basic rules to follow when using anonymous types

  • Anonymous types must have an initial value, and this value cannot be null because the type is inferred from the initializer
  • Anonymous types can be used for simple types or complex types. However, it is of little value when used to define simple types
  • A composite anonymous type requires a member declaration. For example, var joe = new {Name="Joe"}
  • Anonymous types support only aware technology
  • Anonymous types cannot be used for fields of a class
  • Anonymous types can be used as initializers in a for session
  • You can use the new keyword; Array initializers must use the new keyword
  • Anonymous types can be used for arrays
  • All anonymous types are derived from Object types
  • Method can return anonymous type, but it needs to be converted to object, which breaks the strong typing principle
  • Methods can be added to initialize anonymous types, but only so-called linguists may be interested in this approach

2. Use anonymous type

2.1 defining simple anonymous types

var title = "LINQ Unleashed for C#";

2.2 using array initializer syntax

var fibonacci = new int[]{ 1, 1, 2, 3, 5, 8, 13, 21 };

2.3 create review anonymous type

var dena = new {First="Dena", Last="Swanson"};

2.4 adding methods to anonymous types

This technique defines an anonymous delegate and assigns the anonymous delegate to the generic class Func. In this example, Concat is defined as an anonymous delegate that accepts two strings, splices them together, and then returns a new string. You can assign this delegate to any variable defined as the Func instance (with formal parameters of three substring types). Finally, assign the variable Concat to a member declarator in the anonymous type definition.

Func<string, string, string> Concat = delegate (string first, string last)
{
	return last + ", " + first;
};

var dena = new { First = "Dena", Last = "Swanson", Concat = Concat };
Console.WriteLine(dena.Concat(dena.First, dena.Last));

In addition, reflection mechanism can also be used to obtain information in anonymous delegation:

Func<Type, Object, string> Concat = delegate (Type t, Object o)
{
	var info = t.GetProperties();
	return (string)info[1].GetValue(o, null) + ", " + (string)info[0].GetValue(o, null);
};
var dena = new { First="Dena", Last="Swanson", Concat=Concat };
Console.WriteLine(dena.Concat(dena.GetType(), dena));

2.5 using anonymous type index in For loop

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21 };
for (var i = 0; i < fibonacci.Length; i++)
	Console.WriteLine(fibonacci[i]);

2.6 using anonymous type index in Foreach

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21 };
foreach (var fibo in fibonacci)
	Console.WriteLine(fibo);

Since you want to iterate over an object in a Foreach statement, the only condition you need to satisfy is that the object must implement IEnumerable or IEnumberable. This is also a prerequisite for bindability (such as data binding of GridView). In the following example, both the LINQ query statement and the extension method return an enumerable object.

var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21, 33, 54, 87 };

// uses Lambda expression with Where<int, bool> and Where is an extension method for IEnumerable
foreach (var fibo in fibonacci.Where(n => n % 3 == 0))
	Console.WriteLine(fibo);

// uses LINQ query
foreach (var fibo in from f in fibonacci where f % 3 == 0 select f)
	Console.WriteLine(fibo);

2.7 anonymous types and Using statements

The using statement is a concise representation of try... Finally. The purpose of using try... Finally or using is to ensure that the resource is released before the using block exits or the finally block ends. This can be achieved by calling Dispose, which requires that the object created in the using statement must implement IDisposable.

string connectionString = "Data Source=BUTLER;Initial Catalog=AdventureWorks2000;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
	connection.Open();
	Console.WriteLine(connection.State);
}

2.8 return anonymous type from function

Since the garbage collector cleans up any object, anonymous types can be returned from functions. However, outside the definition scope, an anonymous type indicates an instance of an object. Unfortunately, returning an object will only make you aware of technology five bears, and will also batch gray the strong typing feature of anonymous types. Although you can rediscover the function of the anonymous type through reflection, it will also make this comfortable thing less comfortable.

static void Main(string[] args)
{
	var anon = GetAnonymous();
	var t = anon.GetType();
	Console.WriteLine(t.GetProperty("Stock").GetValue(anon, null));
}

public static object GetAnonymous()
{
	var stock = new { Stock = "MSFT", Price = "32.450" };
	return stock;
}

2.9 anonymous data binding

var quote1 = new { Stock = "DELL", Quote = GetQuote("DELL") };
var quote2 = new { Stock = "MSFT", Quote = GetQuote("MSFT") };
var quote3 = new { Stock = "GOOG", Quote = GetQuote("GOOG") };

var quotes = new object[] { quote1, quote2, quote3 };
DataList1.DataSource = quotes;
DataList1.DataBind();

2.10 testing the equality of anonymous types

The equality of anonymous types is strictly defined. Two anonymous types are considered Equal if they have the same member declaration order, member variables, member projection type, and member name. In this case, you can use the reference equality operator. If you want to test the equality of members, you can use the Equal method. For anonymous types with the same order / type and name / type, the value of member declarator will also produce the same hash value; These hash values are the basis of equality testing.

var audioBook1 = new { Artist = "Bob Dylan", Song = "I Shall Be Released" }; 	// Label1
var audioBook2 = new { Song = "I Shall Be Released", Artist = "Bob Dylan" }; 	// Label2
var songBook1 = new { Artist = "Bob Dylan", Song = "I Shall Be Released" };		// Label3
var songBook2 = new { Singer = "Bob Dylan", Song = "I Shall Be Released" };		// Label4

Console.WriteLine("====================Variable type====================");
Console.WriteLine("audioBook Type: " + audioBook1.GetType().ToString());
Console.WriteLine("audioBook Type: " + audioBook2.GetType().ToString());
Console.WriteLine("audioBook Type: " + songBook1.GetType().ToString());
Console.WriteLine("audioBook Type: " + songBook2.GetType().ToString());

Console.WriteLine("====================hash code ====================");
Console.WriteLine("audioBook1 hash " + audioBook1.GetHashCode());
Console.WriteLine("audioBook2 hash " + audioBook2.GetHashCode());
Console.WriteLine("songBook1 hash  " + songBook1.GetHashCode());
Console.WriteLine("songBook2 hash  " + songBook2.GetHashCode());

Console.WriteLine(audioBook1 == songBook1);
Console.WriteLine(audioBook1.Equals(songBook1));
Console.WriteLine(audioBook1.Equals(songBook2));
Console.WriteLine(songBook1.Equals(songBook2));
Console.WriteLine(audioBook2.Equals(audioBook1));

2.11 use anonymous type through LINQ query

var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
var all = from n in numbers orderby n descending select n;

foreach (var n in all)
	Console.WriteLine(n);

var songs = new string[] { "Let it be", "I shall be released" };
var newType = from song in songs select new { Title = song };

foreach (var s in newType)
	Console.WriteLine(s.Title);

2.12 introduction to generic anonymous methods

Anonymous methods are the same as normal methods except that there is no name. It is a scheme to complete simple tasks by defining delegates, while a complete method means more code. Anonymous methods have developed Lambda expressions.

static void Main(string[] args)
{
	Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

	Console.CancelKeyPress += delegate
	{
		Console.WriteLine("Anonymous Cancel pressed");
	};
	
	Console.ReadLine();
}

static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
	Console.WriteLine("Cancel pressed");
}

2.13 using anonymous generic methods

System.Func<long, long> Factorial = delegate (long n)
{
	if (n == 1) 
		return 1;
		
	long result = 1;
	
	for (int i = 2; i <= n; i++)
		result *= i;
		
	return result;
};

Console.WriteLine(Factorial(6));

2.14 implementation of embedded recursion

In the above example, the calculation is performed using the For loop. In the following example, change the code to use recursion. The biggest difficulty is that this named delegate does not have a name until it is defined. Therefore, the name cannot be used inside the anonymous delegate, but you can still complete the task.

There is a class called StackFrame. StackFrame allows you to get methods from the call stack, that is, you can use this class and reflection to recursively call anonymous delegates.

Func<long, long> Factorial = delegate (long n)
{
   return n > 1 ? n * (long)(new StackTrace().GetFrame(0).GetMethod().Invoke(null, new object[] { n - 1 })) : n;
};

Console.WriteLine(Factorial(6));

Topics: C# linq