C#從零開始_自學C#、Visual Studio實境秀 44/ Getting Started with C# Lesson 16~18 of...



{

14:10 Lesson 16 of 20 Introducing LINQ http://bit.ly/2hhWy5C

{

15:50 Finding Items in Collections

17:00 you're going to need to find items in a collection that meet specific criteria. LINQ provides you with extension methods like Where, Skip, and Take to make this easy.

所以 Where, Skip, Take 這些都屬擴充方法

The Where extension method is the most commonly used.

32:10 The Where extension method is the most commonly used.

34:00 The Where extension method is the most commonly used.

2:09:00 When you filter a list using the Where extension method, the result is an IEnumerable<T>. This is fine if you just want to iterate over the items once, however, you will often need to manipulate those items.

所以 IEnumerable<T> 這一類型的是適合  to iterate over the items once,

36:30 Changing Each Item in Collections

Using the Select method from LINQ, you can change the type of the items in your collections by creating new items or selecting one member of the items.

IEnumerable<string> allFirstNames = people.Select(x => x.FirstName);

40:00 就好像前面學的 anonymous type 的妙用 You can also create a brand new object based on properties you select. For this example, I'll create another model FullName and set the First and Last properties based on the FirstName and LastName properties of the Person model.

選取指定類的某些想要的屬性(based on properties you select),來建構一個新的type

public class FullName

{

public string First { get; set; }

public string Last { get; set; }

}

IEnumerable<FullName> allFullNames = people.Select(x => new FullName { First = x.FirstName, Last = x.LastName });

此例還不是 anonymous type, 乃是 named FullName。若是 anonymous type 則是:(不想概括承受時,又不想建構(composition)一個新的 class 用 anonymous type)

要取幾個屬性,要用逗點隔開。

以下是 anonymous type 的試作:

var allFullNames = people.Select(x => new {x.FirstName, x.LastName });

{

var fullname = people.Select(z => new { z.FirstName, z.LastName });

var fullname1 = from i in people select new { i.FirstName, i.LastName};

foreach (var i in fullname)

{

WriteLine(i);

}

WriteLine("____________");

foreach (var i in fullname1)

{

WriteLine(i);

}

}

具名的就是在 new 後加其名

可見 Where  有 predicate ;而 select 沒有,卻有 new(既然是「 a brand new object 」,當然要有 new 關鍵字)

1:00:00 字形結構換部首 字形結構兼音義 evaluate evaluating,字根其實是 e value ate

1:11:30 Finding One Item in Collections

1:17:20 the FirstOrDefault, LastOrDefault, and SingleOrDefault extension methods from LINQ. These are three of the more commonly used LINQ methods for obtaining one item from a collection.

The FirstOrDefault extension method will return the first element of a set of data. If there are no elements that match your criteria, the result will be the default value type for the object (usually null).

1:31:00 The "OrDefault" means, if no elements in the queried data match the expression passed into the method, the returning object will be null.

The FirstOrDefault method can also be used to filter the list to return the first element that matches your expression's criteria.

1:29:30 總之讓程式愈簡潔、愈易讀就是了:is more concise, and can improve readability of your code.

1:35:10 要確定沒有不符合的項目才能用 First() 否則會傳回例外情形:There is a First extension method that will function the same as FirstOrDefault but will return a System.InvalidOperationException if there are no elements that match your criteria.

1:39:10 The SingleOrDefault extension method will return the only occurrence of an item matching your expression. If none match your criteria, the default value of your type will be returned.

1:40:00 所以沒有把握只有一個符合條件時,別用 SingleOrDefault functions much like FirstOrDefault, but if more than one item matches your predicate, a System.InvalidOperationException will be thrown.

1:52:40 Finding Data About Collections

There are extension methods that allow you to determine if or how many items will satisfy an expression.

1:54:30 The Count extension method

int numberOfPeopleInList = people.Count();

int peopleOverTwentyFive = people.Count(x => x.Age > 25);

都是一個有 predicate 一個沒有的多載擴充方法

1:56:10 The Any extension method checks a set of data and return a boolean value indicating whether any items in the collection match your predicate.

2:00:20 Any() 較 Count() 安全合用:Using Any is a clearer way of checking if elements exist than checking if the count of a list is greater than 0

因為 Count 可能會傳回例外情形

2:05:00 All 則要完全吻合,Any 只要有一吻合即可

2:06:30 Converting Results to Collections

The results of many of the LINQ queries so far has been IEnumerable<T>

LINQ provides you with extension methods that allow you to convert collections to other collection types, and these methods work with any type implementing an IEnumerable interface.

2:07:30 ToList()

The ToList extension method allows you to convert an IEnumerable<T> to a List<T>,

2:12:00 七星大法 空間時間的互換:用在翻譯上

This is where the ToList extension method comes in to play. 這就是ToList擴展方法展現它功能的時候。

用 時候來翻 where !國文能力不好,行嗎?

2:15:10 ToArray

2:46:00 練習成功{

using System;

using static System.Console;

using System.Collections.Generic;

using System.Linq;

public class Program

{

public static void Main()

{

var people = GenerateListOfPeople();



WriteLine("Please key the word of the First name to use for filtering the collection:");

string n= ReadLine();

WriteLine();

List<Person> pr = people.Where(pl=>pl.FirstName.IndexOf(n) > -1).ToList();

foreach(Person pi in pr)

{

WriteLine($"{pi.FirstName }  {pi.LastName }");

}



Write("Total of the peopen is ");ForegroundColor = ConsoleColor.Cyan;WriteLine( people.Count+"\n----------------");ForegroundColor = ConsoleColor.Gray;

rep:

WriteLine("Please key the age to use for filtering the collection:");

int specified_age = 0;

if (int.TryParse(ReadLine(), out int result))

specified_age = result;

else

goto rep;

WriteLine();

// Write your code here

List<Person> pp = people.Where(x => x.Age > specified_age).ToList();

foreach(Person pi in pp)

{

WriteLine($"{ pi.FirstName} {pi.LastName}");

}

Write("Total of the peple is "  );ForegroundColor = ConsoleColor.Cyan; WriteLine(people.Count);ForegroundColor = ConsoleColor.Gray;

WriteLine("____________");

var fullname = people.Select(z => new { z.FirstName, z.LastName });

var fullname1 = from i in people select new { i.FirstName, i.LastName };

foreach (var i in fullname)

{

WriteLine(i);

}

WriteLine("____________");

ForegroundColor = ConsoleColor.Yellow;

var p = fullname.FirstOrDefault(x => x.FirstName.IndexOf("E") > -1);

var p1 = fullname.Where(x => x.FirstName.IndexOf("e") > -1).FirstOrDefault();

//var p2 = fullname.SingleOrDefault(x => x.FirstName.IndexOf("E") > -1);

int p3=0;

if (fullname.Any(x => x.FirstName.IndexOf("e") > -1))

p3 = fullname.Count(x => x.FirstName.IndexOf("e") > -1);

WriteLine($"{p},{p1},{p3}");

ForegroundColor = ConsoleColor.Gray;

foreach (var i in fullname1)

{

WriteLine(i);

}

}



public static List<Person> GenerateListOfPeople()

{

var people = new List<Person>();



people.Add(new Person { FirstName = "Eric", LastName = "Fleming", Occupation = "Dev", Age = 24 });

people.Add(new Person { FirstName = "Steve", LastName = "Smith", Occupation = "Manager", Age = 40 });

people.Add(new Person { FirstName = "Brendan", LastName = "Enrick", Occupation = "Dev", Age = 30 });

people.Add(new Person { FirstName = "Jane", LastName = "Doe", Occupation = "Dev", Age = 35 });

people.Add(new Person { FirstName = "Samantha", LastName = "Jones", Occupation = "Dev", Age = 24 });

people.Add(new Person { FirstName = "Sama", LastName = "Joe", Occupation = "Dev", Age = 24 });

people.Add(new Person { FirstName = "Eve", LastName = "Fleming", Occupation = "Dev", Age = 24 });

people.Add(new Person { FirstName = "George", LastName = "Smith", Occupation = "Manager", Age = 40 });

people.Add(new Person { FirstName = "Ban", LastName = "Enrick", Occupation = "Dev", Age = 30 });

people.Add(new Person { FirstName = "Jan", LastName = "Doe", Occupation = "Dev", Age = 35 });

people.Add(new Person { FirstName = "Oscar", LastName = "Sun", Occupation = "Dev", Age = 45 });



return people;

}

}



public class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

public string Occupation { get; set; }

public int Age { get; set; }

}

}

}



1:13:00 字頻改善,清除符號效能問題。 改善後,類似的資料,由原來須一個多鐘頭、甚至更多,變成了 7 分多鐘!主要在清除符號上的影響,由原來的 for each char in characters  char.delete 到 find.execute 。尤其段落符號多達十四萬多時, 即使 find.execute 也得花上恐怕近半個鐘頭。略去不處理後,效能明顯提昇。除非有必要清除段落符號,否則固然可以略過不處理,焦點放在字頻即可。



2:47:00 Lesson 17 of 20 When and How to use Exceptions http://bit.ly/2hjuwGU 例外情形

{

2:48:40 You use the special throw command to interrupt the normal execution of the program when error ocurrs.

2:59:00  using a try-catch block

The first block of code, called a try block, is where you put all of your code that may throw an exception. If an exception is thrown in the try block, your program will immediately jump into your catch block.

3:02:20 the (System.Exception ex) variable declaration

, which gives you access to the details of the exception during the catch block by using the ex variable.

3:04:00 re-throw :If you have a solution to the issue, your code can correct the state of things to allow your program to continue. If your code cannot resolve the error, you should re-throw the exception.

To do this, you use the throw statement on its own line without giving it an exception

// do something here before re-throwing

3:06:10 catch 不能亂用:If your code isn't going to respond to or log the exception in any way, don't catch the exception in the first place.

InnerException property、 the previous exception:Throwing a new exception will replace the previous exception, so only do this if you're using an exception specific to your application (and make sure to set the InnerException property of your new exception to the previous exception.

記錄例外情形,如何記錄呢?It is common to log exceptions that occur, so that you can review them later and improve the program to avoid them, if possible.

4:00:00 不要濫用 throw :It is important that you only throw exceptions when it's appropriate, when your code is in an unintended situation.

If the situation seems likely, but requires taking a certain action, just handle it using normal application flow control elements like if statements. 當可以用 if 來解決時,就不要用 throw ,因為 When you throw an exception, there is always the chance that the exception will go unhandled, so be careful to throw exceptions only when it feels appropriate.

4:02:00 選擇適當的時機才用 throw :A rule of thumb for determining if you need to throw an exception is if you encounter a situation in a method that doesn't allow you to return a valid result. In that case, an exception may be the best solution, or you may need to reconsider what your method is returning.

3:38:50 若要自己擲出例外情形,要非常謹慎使用:If an exception is thrown from inside of your catch block, the details of the original exception will be lost, so it's important to use caution.

If you want to catch a low-level exception and throw one more relevant to your program, make sure to assign the low-level one to the InnerException property of the new exception.

也就是將舊的、系統原預設的 exception 要記錄在 new exception 的 InnerException 屬性中! This will keep the information available should an investigation be necessary.

try

{

}

catch (ArgumentNullException ex)

{

throw new UserRequiredException(ex); // InnerException property set by constructor

}

3:44:20 Most exception classes will take another exception as a constructor parameter allowing you to pass in the InnerException.

一旦藉由建構子設定了 InnerException 屬性,它就會變成唯讀的: In order to avoid losing the information, the InnerException property of exceptions is read-only, once set by the constructor.

If you're not handling the exceptions at the time that you've caught it, you generally want to just rethrow it like this:

try

{

}

catch (ArgumentNullException ex)

{

Logger.LogError(ex); // log the error before rethrowing 記錄例外情形

throw;

}

Taking this approach will preserve the previous exception, so very little is lost by logging what happened.



3:09:59 Throwing Exceptions

When you're in one of those unexpected situations and your code cannot (or should not) handle this situation itself, it's time to throw an exception.

public List<People> GetAllCustomersByAge(int age)

{

if (age < 18 || age > 150)

{

throw new ArgumentOutOfRangeException("Age must be between 18 and 150.", nameof(age));//逗號即分隔兩個引數

}

}

When throwing exceptions, you use the throw keyword to indicate that you're throwing an exception followed by the Exception object you're throwing.

因為是 Exception object 所以用 new 。

In the example above, the exception object is being created on the same line on which it's thrown.

Also notice that a specific type was used here, the ArgumentOutOfRangeException. This means that anyone catching the exception knows that an argument received was not within the expected range.

Some exception types, like the ArgumentOutOfRangeException, take additional arguments in their constructors.

3:16:00 絕對不要直接丟出以下之例外情形執行個體:Never throw System.Exception, System.SystemException, or ApplicationException directly;

use more specific standard exceptions or custom exceptions. 所以還有自訂的 exception

所以特定、指明的例外情形有助於處理、對症下藥 :This allows callers to choose which exceptions they can handle instead of needing to respond to all exceptions.

可見以上3個(System.Exception, System.SystemException, ApplicationException )是所有的 all exceptions.

3:19:10 The Finally Block

釋放資源:In your code, you may need to ensure you've cleaned up and released any resources you had allocated, whether you threw an exception or not.

{

try

{

throw new Exception("Let's play catch!");

}

catch (System.Exception ex)

{

Console.WriteLine(ex.Message);

}

finally

{

// This code will always run

// even if your catch block re-throws

Console.WriteLine("FINALLY!");

}

// Code here will run only if catch doesn't re-throw

Console.WriteLine("Still ran.");

}

3:25:00 be careful to not throw an exception in the finally block.

3:27:40 finally 就是怎樣它都會執行,且會比 return 早執行:once your program reaches the try block, the finally block will execute before returning, even if your method's return statement is inside the try block or the catch block.

try

{

}

finally

{

// This code will always run - even after exceptions

}

// Code here will run only if no exceptions are thrown

3:31:00 釋放資源 IDisposable interface:In most cases, resources that need to be cleaned up will use .NET's IDisposable interface, and can be wrapped in a using block.

using block 就是 using Statement (C# Reference) http://bit.ly/2uQQvd9

3:38:20 Throwing From Catch Blocks

Your catch blocks can include any code statements, including code that directly throws an exception or calls to other methods that could throw exceptions.

3:46:00 If you're not handling the exceptions at the time that you've caught it, you generally want to just rethrow it like this:

re-throw



3:49:40 Catching Specific Exceptions

3:51:00 In the previous examples, you usually saw catch (System.Exception), which uses polymorphism, the programming concept you learned about from the lesson on Objects and Classes. Knowing that, you also know that you can pass any exception that inherits from System.Exception, and it can be used there as well. If you want to be more specific you can be. Our System.FormatException did exactly that.

When you catch a specific exception, it will only catch the exceptions of that specific type (or ones that inherit from it).

3:52:00 catch 可以有二個 :

try

{

}

catch (System.FormatException)

{

// Handle only FormatExceptions here

}

catch (System.Exception)

{

// Handle all other exceptions here

}

3:53:00 雖然可以有二個以上的 catch ,但只有一個會處理例外情形 :The order of the catch blocks is important; only one catch block can catch an exception. The first catch block that can handle the exception will execute; any others are ignored.

3:55:00 同時處理兩個以上的異常(例外情形),用 when 子句:In some instances you may want to handle more than one type of specific exception the same way and their common exception ancestor class is only System.Exception. In order to that, you use the when clause followed by a condition explaining when you want to use that catch block. It looks like this:

try

{

}

catch (Exception ex) when (ex is MemberNameNotFoundException || ex is FormatException)

{

// Handle only MemberNameNotFoundException and FormatException here

}

和 if 一樣,條件句後接 parentheses 小括弧。 is 關鍵字

3:58:10 When to Avoid Throwing and Catching

4:19:30 當你拋出一個例外情形時,都會有例外情形未被處理的可能,所以只有在合適的時機下才小心地拋出異常。

When you throw an exception, there is always the chance that the exception will go unhandled, so be careful to throw exceptions only when it feels appropriate.

將示例摸索如下:{

using System;

using static System.Console;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;



public class Program

{

public static void Main()

{

//SetMemberBirthday(234,DateTime.Today);

SetMemberBirthdayLogger(234, DateTime.Today);

}

static List<Member> _memberList=new List<Member> ();

public static void SetMemberBirthday(int memberId, DateTime birthday)

{//A rule of thumb for determining if you need to throw an exception is if you encounter a situation in a method that doesn't allow you to return a valid result. In that case, an exception may be the best solution

int id = memberId;

Member member = _memberList.SingleOrDefault(m => m.Id == memberId);

if (member == null)

{

throw new MemberNotFoundException(id);//this is just unhandled :When you throw an exception, there is always the chance that the exception will go unhandled, so be careful to throw exceptions only when it feels appropriate.

}

member.Birthday = birthday;

}



public static bool SetMemberBirthdayLogger(int memberId, DateTime birthday)//you may need to reconsider what your method is returning

{

Member member = _memberList.SingleOrDefault(m => m.Id == memberId);

if (member == null)

{//未找到 Logger 是何類別,怎麼用!只好自己依樣畫葫蘆, composition class Logger

Logger.LogWarning($"SetMemberBirthday Error: Member {memberId} not found. Birthday not set {birthday}.");

return false; // false tells the caller that the operation failed.

}

member.Birthday = birthday;

return true;

}

}



internal class Logger

{

internal static void LogWarning (string message)

{

WriteLine(message);

}

}



[Serializable]

internal class MemberNotFoundException : Exception

{

private object id;



public MemberNotFoundException()

{

}



public MemberNotFoundException(object id)

{

this.id = id;

}



public MemberNotFoundException(string message) : base(message)

{

}



public MemberNotFoundException(string message, Exception innerException) : base(message, innerException)

{

}



protected MemberNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)

{

}

}



class Member

{

internal int Id { get; set; }

internal DateTime Birthday { get; set; }

}



}

4:47:00 Creating Your Own Exceptions 前面摸索的即有系統幫我們建構的自訂 exception

In order to create your own exceptions, you simply inherit from the Exception class or from a more-specific exception class like this:

public class MemberNameNotFoundException : Exception

{

public MemberNameNotFoundException(string memberName)

: base($"Could not find member: {memberName}.")

{}

}

摸索:

public static void SetMemberBirthday(int memberId, DateTime birthday)

{//A rule of thumb for determining if you need to throw an exception is if you encounter a situation in a method that doesn't allow you to return a valid result. In that case, an exception may be the best solution

int id = memberId;

Member member = _memberList.SingleOrDefault(m => m.Id == memberId);

if (member == null)

{

throw new MemberNotFoundException(id);//this is just unhandled :When you throw an exception, there is always the chance that the exception will go unhandled, so be careful to throw exceptions only when it feels appropriate.

}

member.Birthday = birthday;

}

internal class MemberNotFoundException : Exception

{

internal MemberNotFoundException(int id) : base($"Could not find member: {id}.") { }

}

throw 要接著 new 因為是建構一個 exception 的 instance.

4:56:00 所以 throw exception 是一定要 handle 的 :so you throw an exception that the caller can catch and handle.

5:11:00 摸索{

public static void Main()

{

addMember();

SetMemberBirthday(234,DateTime.Today);

SetMemberBirthdayLogger(234, DateTime.Today);

}

static List<Member> _memberList=new List<Member> ();

public static void addMember()

{

string name = "George";

try

{

int memberId = membersOnlyList.GetMemberIdByName(name);

Console.WriteLine($"Come on in member, {memberId}");

}

catch(MemberNameNotFoundException)

{

WriteLine($"You're not on the list,{name}");

}

}

class membersOnlyList

{

public static int GetMemberIdByName(string memberName)

{

Member member = _memberList.SingleOrDefault(m => m.Name == memberName);

if (member != null)

{

return member.Id;

}

throw new MemberNameNotFoundException(memberName);

}

}

}

5:13:00 In some cases, you may want to wrap low level exceptions with your own exceptions that are more specific to your application's model. In that case, you probably will want to retain the information from the original exception. In that case, be sure to include a constructor in your custom exception type that accepts an exception argument and sets the InnerException property. It would look like this:

5:59:00 5:40:00 練習成功:{

using System;

using static System.Console;

using System.Collections.Generic;

using System.Linq;



public class Program

{



public static void Main()

{

var p = Program.GetAccessPermissions("WriteLessons");

//Program.GetAccessPermissions(String.Empty);

foreach (var i in p)

WriteLine(i);

}

public static List<string> GetAccessPermissions(string token)

{

// check token validity here and throw exceptions as needed.

if (String.IsNullOrEmpty( token))//The first should be thrown if the token is null or empty

{

throw new MyMissingTokenException(token);

}

/*The second should be thrown if the token exists, but doesn't meet some criteria

 of your choosing (for instance, minimum and/or maximum length). */





try { Token.checkToken(token); }

catch (MyInvalidTokenException)

{

WriteLine($"{token} is a invalid token!");

}

return new List<string> { "ReadLessons", "ReviewLessons" };

}

}



class Token

{

internal static List<string> tokenList = new List<string>() { "testToken", "WriteLessons" };

internal static void checkToken(string token)

{

var p = tokenList.SingleOrDefault(x => x == token);

if (p!=null)

{

if (p.Length  <12) { throw new MyInvalidTokenException(token); }

}



}



}



class MyMissingTokenException : ArgumentException

{

internal MyMissingTokenException(string token):base ($"Your token {token} is missing!") { }

}

class MyInvalidTokenException : ArgumentException

{

internal MyInvalidTokenException(string token) : base($"Your token {token} is invalid!") { }

}

}



}

6:00:00 Lesson 18 of 20 Testing Your Code http://bit.ly/2voXpbe

{

6:01:30 Unit Testing Your Code

測試有以下幾種:integration tests, web tests, performance/load tests, and, the one covered in this lesson, unit tests.

Test Driven Development, or TDD

6:08:00 Unit tests are a great way to prevent and catch bugs during feature development as well as general refactoring.

6:09:50 use the xunit testing framework. There is some configuration you will need to do in order to add the Xunit references and run these tests from the dotnet CLI.



}



}


留言

熱門文章