Hiển thị các bài đăng có nhãn C#. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn C#. Hiển thị tất cả bài đăng

Thứ Hai, 18 tháng 4, 2011

Các cách sử dụng file .htaccess bạn nên biết

File .htaccess(hypertext access) của apache là một công cụ cực kỳ hữu dụng. File .htaccess thường được tìm thấy trong thư mục root của website, bạn có thể dễ dàng sửa chữa nó bằng bất kỳ text editor nào. Bạn nên sao lưu lại file .htaccess của mình trước khi thử nghiệm các cách hack dưới đây.

1. Ngăn chặn hotlink

Nhiều người copy ảnh từ server của bạn và đưa lên trang web của họ. Thêm vào .htaccess đoạn mã dưới đây sẽ giúp bạn ngăn chặn ảnh hiển thị trên website khác
Options +FollowSymlinks
#Ngăn chặn hotlink
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?vannyneo.com/ [nc]
RewriteRule .*.(gif|jpg|png)$ http://vannyneo.com/img/stop_stealing_bandwidth.gif[nc]

2. 301 Redirect

Nếu bạn chuyển domain, hoặc chỉ muốn chuyển một trang cũ về một trang mới và không muốn lo lắng về các kết quả search từ google, sử dụng đoạn mã sau
Redirect 301 /d/file.html http://www.vannyneo.com/r/file.html

3. Chuyển hướng từ tên miền cũ sang tên mới

Sử dụng đoạn mã dưới đây bạn có thể chuyển tất cả các link từ tên miền cũ sang tên miền mới:
#Chuyển hướng từ tên miền cũ sang tên mới
RewriteEngine On
RewriteRule ^(.*)$ http://www.vannyneo.com/$1 [R=301,L]

4. Tạo trang báo lỗi riêng

Bạn không muốn dùng các trang báo lỗi có sẵn của host, bạn có thể tạo các trang báo lỗi riêng và cấu hình vào file htaccess như sau:
ErrorDocument 401 /error/401.php
ErrorDocument 403 /error/403.php
ErrorDocument 404 /error/404.php
ErrorDocument 500 /error/500.php

5. Cấm IP truy cập

Nếu có 1 IP thường xuyên spam website của bạn, bạn có thể cấm IP đó như dòng 2, hoặc cấm 1 dải IP như dòng 3:
allow from all
deny from 113.190.183.138
deny from 113.190

6. Đặt email mặc định cho server admin

Sử dụng đoạn mã sau
ServerSignature EMail
SetEnv SERVER_ADMIN default@vannyneo.com

7. Bảo vệ file

Đoạn mã dưới đây sẽ từ chối khi người dùng truy cập vào bất kỳ file nào và gửi về lỗi 403.
#Bảo vệ .htaccess File

order allow,deny
deny from all
5

8. Đặt mã cho thư mục và file

Bạn có thể đặt mã & quyền truy cập vào thư mục/file như sau:
# Đặt mã cho thư mục
resides
AuthType basic
AuthName "Thư mục này đã được bảo vệ"
AuthUserFile /home/path/.htpasswd
AuthGroupFile /dev/null
Require valid-user
# Đặt mã cho file

AuthType Basic
AuthName "Prompt"
AuthUserFile /home/path/.htpasswd
Require valid-user

9. Đặt trang mặc định

Bạn có thể đặt trang web mặc định cho thư mục nào đó. Ví dụ đặt file about.html thay cho file index.html:
#Đặt trang mặc định (index)
DirectoryIndex about.html

10. Nén file bằng cách bật Gzip

Bằng cách bật Gzip bạn có thể nén file từ server giúp cho việc tải trang nhanh hơn
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

11. Bỏ "category" ở URL

Để chuyển url từ: http://vannyneo.com/category/tong-hop về -> http://vannyneo.com/tong-hop, bạn chỉ cần thêm vào file .htaccess đoạn mã sau
RewriteRule ^category/(.+)$ http://www.vannyneo.com/$1 [R=301,L]

12. Bỏ phần đuôi file ở URL

Bạn mới lập trình php và không muốn hiện .php ở url, hãy thêm đoạn code sau:
RewriteRule ^(([^/]+/)*[^.]+)$ /$1.php [L]

13. Thêm / vào cuối URL

Một vài bộ máy tìm kiếm (như Yahoo)tự động bỏ dấu / ở cuối url. Website của bạn cũng có thể được truy cập có hoặc không có dấu / ở sau cùng url. Điều này không tốt với các bộ máy tìm kiếm (sẽ bị coi là duplicated content). Thêm đoạn mã dưới đây vào .htaccess để giải quyết vấn đề đó
#Thêm / vào cuối URL
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !#
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://vannyneo.com/$1/ [L,R=301]

14. Bỏ www ở URL

Nếu bạn muốn chuyển mọi truy cập từ http://www.example.com thành http://example.com, thêm đoạn mã sau vào file .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]

15. Thêm www vào URL

Tất nhiên nếu bạn muốn ngược lại "14" bạn có thể dùng đoạn mã sau
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www.example.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]

16. Không cho "browse" thư mục

Để ngăn chặn truy cập vào tên file trong thư mục nào đó (ví dụ thư mục plugins của wordpress), thêm đoạn mã sau vào file .htacess:
Options All -Indexes


ở file .htaccess bạn thêm vào:
order allow,deny
deny from [ip cần cấm]
deny from [1 ip khác]
deny from [1 vài ip khác]
allow from all

cấu trúc IP VD: 210.245.24.22
order deny,allow
deny from all
allow from 58.186.101.237
allow from 58.186.101.236

Liên kết

Thứ Ba, 3 tháng 3, 2009

Làm thế nào để Declare, Instantiate, và sử dụng là một Delegate

Trong C# 1.0 và trở về sau, các delegate có thể được kê khai như trong ví dụ sau.

// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
          Console.WriteLine("Notification received for: {0}", name);
}

// Create an instance of the delegate.
Del del1 = new Del(Notify);

C# 2.0 cung cấp một cách đơn giản để viết delegate trước đó, như trong ví dụ sau.

// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

Trong C# 2.0 và sau, nó cũng có thể sử dụng một method anonymous để khai báo và khởi tạo là một delegate, như trong ví dụ sau.

// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name) { Console.WriteLine("Notification received for: {0}", name); };

Trong C# 3.0 và sau, các delegate cũng có thể được khai báo và khởi tạo bằng cách sử dụng là một biểu thức lambda, như trong ví dụ sau.

// Instantiate Del by using a lambda expression.
Del del4 = name => { Console.WriteLine("Notification received for: {0}", name); };

Việc sử dụng các các delegate phát huy tốt chức năng tách giữa các cơ sở dữ liệu mã hiệu sách và các khách hàng. Mã khách hàng không có kiến thức về cách các cuốn sách được lưu trữ hoặc làm thế nào mã hiệu sách tìm thấy cuốn sách bìa mềm. Các mã hiệu sách không có kiến thức về những gì xử lý được thực hiện trên những cuốn sách bìa mềm sau khi nó tìm thấy chúng.

// A set of classes for handling a bookstore:
namespace Bookstore
{
       using System.Collections;

       // Describes a book in the book list:
       public struct Book
       {
               public string Title; // Title of the book.
               public string Author; // Author of the book.
               public decimal Price; // Price of the book.
               public bool Paperback; // Is it paperback?

               public Book(string title, string author, decimal price, bool paperBack)
               {
                      Title = title;
                      Author = author;
                      Price = price;
                      Paperback = paperBack;
               }
        }

        // Declare a delegate type for processing a book:
        public delegate void ProcessBookDelegate(Book book);

        // Maintains a book database.
        public class BookDB
        {
               // List of all books in the database:
               ArrayList list = new ArrayList();

               // Add a book to the database:
               public void AddBook(string title, string author, decimal price, bool paperBack)
               {
                      list.Add(new Book(title, author, price, paperBack));
               }

               // Call a passed-in delegate on each paperback book to process it:
               public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
               {
                      foreach (Book b in list)
                      {
                             if (b.Paperback)
                                   // Calling the delegate:
                                   processBook(b);
                      }
               }
        }
}

// Using the Bookstore classes:
namespace BookTestClient
{
       using Bookstore;

       // Class to total and average prices of books:
       class PriceTotaller
       {
               int countBooks = 0;
               decimal priceBooks = 0.0m;

               internal void AddBookToTotal(Book book)
               {
                       countBooks += 1;
                       priceBooks += book.Price;
               }

               internal decimal AveragePrice()
               {
                       return priceBooks / countBooks;
               }
        }

         // Cla ss to test the book database:
         class TestBookDB
         {
                // Print the title of the book.
                static void PrintTitle(Book b)
                {
                         System.Console.WriteLine(" {0}", b.Title);
                }

                // Execution starts here.
                static void Main()
                {
                           BookDB bookDB = new BookDB();
          
                           // Initialize the database with some books:
                           AddBooks(bookDB);
                           // Print all the titles of paperbacks:
                           System.Console.WriteLine("Paperback Book Titles:");

                           // Create a new delegate object associated with the static
                           // method Test.PrintTitle:
                           bookDB.ProcessPaperbackBooks(PrintTitle);
                           // Get the average price of a paperback by using
                           // a PriceTotaller object:
                           PriceTotaller totaller = new PriceTotaller();
                           // Create a new delegate object associated with the nonstatic
                           // method AddBookToTotal on the object totaller:
                           bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

                           System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",
                           totaller.AveragePrice());
                  }

                 // Initialize the book database with some test books:
                 static void AddBooks(BookDB bookDB)
                 {
                         bookDB.AddBook("The C Programming Language", 
                                  "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
                         bookDB.AddBook("The Unicode Standard 2.0", 
                                  "The Unicode Consortium", 39.95m, true);
                         bookDB.AddBook("The MS-DOS Encyclopedia", 
                                  "Ray Duncan", 129.95m, false);
                         bookDB.AddBook("Dogbert's Clues for the Clueless", 
                                  "Scott Adams", 12.00m, true);
                  }
         }
}
/* Output:
Paperback Book Titles:
The C Programming Language
The Unicode Standard 2.0
Dogbert's Clues for the Clueless
Average Paperback Book Price: $23.97
*/

DangTrung.

Classes và cấu trúc

Các lớp học và cấu trúc là hai trong số các cấu trúc cơ bản của hệ thống kiểu thông dụng trong các .NET Framework. Mỗi bản chất là một cấu trúc dữ liệu mà gói gọn một tập hợp các dữ liệu và hành vi thuộc về nhau như một đơn vị logic. Các dữ liệu và hành vi là những thành viên của lớp hoặc cấu trúc, và chúng bao gồm các phương pháp, thuộc tính, và các sự kiện, vân vân, được liệt kê sau trong chủ đề này.

Một class khi khai báo cấu trúc giống như một kế hoạch chi tiết được sử dụng để tạo ra các trường hợp hoặc các đối tượng lúc thực thi. Nếu bạn định nghĩa một class hoặc cấu trúc được gọi là Person, Person là tên của kiểu. Nếu bạn khai báo và khởi tạo một biến p của Person, p được cho là một đối tượng hoặc thể hiện của Person. Nhiều trường hợp của các kiểu cùng một người có thể được tạo ra, và mỗi trường hợp có thể có giá trị khác nhau trong thuộc tính và các trường nó.

Lớp là một kiểu tham chiếu. Khi một đối tượng của lớp được tạo ra, biến mà đối tượng được giao nắm giữ chỉ là một tham chiếu đến bộ nhớ. Khi các tham chiếu đối tượng được gán cho một biến mới, biến mới liên quan đến các đối tượng ban đầu. Thay đổi được thực hiện thông qua một biến được phản ánh trong các biến khác, bởi vì cả hai đều đề cập đến cùng một dữ liệu.

Struct A là một kiểu giá trị. Khi cấu trúc được tạo ra, biến mà cấu trúc được phân công giữ cấu trúc của dữ liệu thực tế. Khi cấu trúc lại được giao cho một biến mới, đó là sao chép. Các biến mới và thay đổi bản gốc do đó có hai bản sao riêng biệt của cùng dữ liệu. Thay đổi được thực hiện cho một bản sao không ảnh hưởng đến các bản sao khác.

Nhìn chung, các lớp học được sử dụng để mô hình hành vi phức tạp hơn, hoặc dữ liệu được dự định được sửa đổi sau khi một đối tượng lớp được tạo ra. Struct phù hợp nhất để cấu trúc dữ liệu nhỏ có chứa chủ yếu là dữ liệu mà không có ý định được sửa đổi sau khi các cấu trúc được tạo ra.

Trong ví dụ sau đây, MyCustomClass được xác định với ba thành viên ở cấp cao nhất của namespace ProgrammingGuide. Một cá thể (object) của MyCustomClass được tạo ra trong các method chính trong chương trình class, và method của object và thuộc tính được truy cập bằng cách sử dụng ký hiệu dấu chấm.

namespace ProgrammingGuide
{
        // Class definition.
        public class MyCustomClass
        {
               // Class members: Property.
               public int Number { get; set; }

               // Method.
               public int Multiply(int num)
               {
                        return num * Number;
               }

               // Instance Constructor.
               public MyCustomClass()
               {
                       Number = 0;
               }
         }
         // Another class definition. This one contains
         // the Main method, the entry point for the program.
         class Program
         {
                static void Main(string[] args)
                {
                        // Create an object of type MyCustomClass.
                        MyCustomClass myClass = new MyCustomClass();

                        // Set the value of a public property.
                        myClass.Number = 27;

                        // Call a public method.
                        int result = myClass.Multiply(4);
                }
        }
}

Thành viên

Tất cả các method, các trường, constants, tài sản, và các sự kiện phải được khai báo trong phạm vi kiểu là một, chúng được gọi là các thành viên của lớp học hoặc struct. Trong C #, không có biến toàn cục hoặc các phương pháp như có trong một số ngôn ngữ khác. Ngay cả chỉ mục của chương trình, phương pháp chính, phải được khai báo trong một lớp hoặc Struct. Danh sách sau đây bao gồm tất cả các loại của các thành viên có thể sẽ được kê khai trong một lớp học hoặc Struct.
  • Fields
  • Constants
  • Properties
  • Methods
  • Constructors
  • Destructors
  • Events
  • Indexers
  • Operators
  • Nested Types

DangTrung.

Thứ Hai, 2 tháng 3, 2009

Làm thế nào để truy cập một Class Collection với foreach

Các ví dụ mã sau minh họa làm thế nào để viết một lớp tổng quát mà có thể được sử dụng với foreach. Lớp học là một tokenizer chuỗi, tương tự như chức năng strtok_s C run-time.

Trong ví dụ sau đây, Tokens chia các câu "Đây là một câu ví dụ." vào thẻ bằng cách sử dụng '' và '-' là dấu phân cách, và liệt kê những thẻ bài bằng foreach:

Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
      System.Console.WriteLine(item);
}

Trong nội bộ, Tokens sử dụng một mảng, mà thực hiện IEnumerator và IEnumerable chính nó. Ví dụ mã có thể đã sử dụng phương pháp liệt kê của mảng như là của riêng nó, nhưng mà có thể đã thất bại nhằm mục đích của ví dụ này.

Trong C#, nó không phải là hoàn toàn cần thiết để một class collections để kế thừa từ IEnumerable và IEnumerator để tương thích với foreach. Khi lớp có GetEnumerator yêu cầu, MoveNext, Reset, và các thành viên hiện tại, nó sẽ làm việc với foreach. Bỏ qua các interface có lợi thế là cho phép bạn xác định kiểu trả về của hiện tại để được nhiều hơn so với đối tượng cụ thể, cung cấp kiểu an toàn.

Ví dụ, bắt đầu với ví dụ mã trước đó trong chủ đề này, thay đổi những dòng này:

// No longer inherits from IEnumerable:
public class Tokens
// Doesn't return an IEnumerator:
public TokenEnumerator GetEnumerator()
// No longer inherits from IEnumerator:
public class TokenEnumerator
// Type-safe: returns string, not object:
public string Current

Bây giờ, bởi vì trả về một chuỗi hiện tại, các trình biên dịch có thể phát hiện khi một kiểu không tương thích được sử dụng trong một câu lệnh foreach:

// Error: cannot convert string to int:
foreach (int item in f)

Những bất lợi của IEnumerable và IEnumerator bỏ qua là các class collections không còn tương thích với các câu lệnh foreach, hoặc tương đương, của các ngôn ngữ khác ngôn ngữ thông dụng khi chạy tương thích.

Bạn có thể có tốt nhất của cả hai thế giới, kiểu an toàn trong C# và khả năng tương tác với các ngôn ngữ khác ngôn ngữ phổ biến thời gian chạy tương thích, do thừa kế từ IEnumerable và IEnumerator và sử dụng giao diện thực hiện rõ ràng như thể hiện trong ví dụ sau đây.

using System.Collections;


// Declare the Tokens class:
public class Tokens : IEnumerable
{
       private string[] elements;


       Tokens(string source, char[] delimiters)
       {
               // Parse the string into tokens:
               elements = source.Split(delimiters);
       }


       // IEnumerable Interface Implementation:
       // Declaration of the GetEnumerator() method
       // required by IEnumerable
       public IEnumerator GetEnumerator()
       {
               return new TokenEnumerator(this);
        }


        // Inner class implements IEnumerator interface:
        private class TokenEnumerator : IEnumerator
        {
               private int position = -1;
               private Tokens t;


               public TokenEnumerator(Tokens t)
               {
                      this.t = t;
               }


               // Declare the MoveNext method required by IEnumerator:
               public bool MoveNext()
               {
                     if (position < t.elements.Length - 1)
                     {
                             position++;
                             return true;
                     }
                     else
                     {
                             return false ;
                     }
               }
               // Declare the Reset method required by IEnumerator:
               public void Reset()
               {
                     position = -1;
               }


               // Declare the Current property required by IEnumerator:
               public object Current
               {
                      get
                      {
                             return t.elements[position];
                      }
                }
          }
          // Test Tokens, TokenEnumerator
          static void Main()
          {
                // Testing Tokens by breaking the string into tokens:
                Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
  
                foreach (string item in f)
                {
                           System.Console.WriteLine(item);
                }
         }
}
/* Output:
This
is
a
sample
sentence.
*/

DangTrung.

Collection Classes

.NET Framework cung cấp các classes chuyên dùng cho việc lưu trữ dữ liệu và phục hồi. Các classes này cung cấp hỗ trợ cho stacks, queues, lists, và HashTable. Hầu hết classes collection thực hiện tương tự các interfaces, và các interfaces này có thể được thừa kế để tạo ra các classes collection mới phù hợp với nhu cầu lưu trữ dữ liệu chuyên sâu hơn.

CHÚ Ý : Các ứng dụng hướng phiên bản 2.0 và sau này của NET Framework. nên sử dụng các classes collection Thuộc trong namespace System.Collections.Generic, cung cấp nhiều kiểu an toàn và hiệu quả hơn so với counterparts của họ không tổng quát.

ArrayList list = new ArrayList();
list.Add(10);
list.Add(20);

Tổng quan Collection Classes :

Collections có các thuộc tính sau :
  • Collection các classes được định nghĩa như là một phần của namespace System.Collections hoặc System.Collections.Generic.
  • Hầu hết các classes collection xuất phát từ interface ICollection, IComparer, IEnumerable, IList, IDictionary, và IDictionaryEnumerator và tương đương tổng quát của họ.
  • Collection Classe cung cấp an toàn và trong một số trường hợp có thể cung cấp hiệu suất tốt hơn, đặc biệt là khi họ lưu trữ giá trị các loại.

Collections và Cấu trúc dữ liệu :
  • Chặt chẽ dữ liệu liên quan có thể được xử lý hiệu quả hơn khi được nhóm lại với nhau thành một bộ sưu tập. Thay vì viết mã riêng biệt để xử lý các đối tượng riêng biệt, bạn có thể sử dụng cùng một mã để xử lý tất cả các yếu tố của một bộ sưu tập.
  • Để quản lý một bộ sưu tập, sử dụng lớp System.Array và các lớp trong System.Collections, System.Collections.Generic, và các không gian tên System.Collections.Concurrent để thêm, xóa, và sửa đổi hoặc các yếu tố cá nhân hoặc một loạt các yếu tố trong bộ sưu tập. Một bộ sưu tập toàn bộ thậm chí có thể được sao chép vào bộ sưu tập khác.
  • Một số lớp học System.Collections có khả năng phân loại, và hầu hết được lập chỉ mục. Quản lý bộ nhớ được xử lý tự động, và năng lực của các bộ sưu tập được mở rộng theo yêu cầu. Đồng bộ hóa cung cấp an toàn đề khi truy cập vào các thành viên của bộ sưu tập. Một số lớp học System.Collections có thể tạo ra loại giấy gói mà làm cho bộ sưu tập chỉ đọc hoặc kích thước cố định. Bất kỳ lớp System.Collections có thể tạo ra điều tra riêng của mình mà làm cho nó dễ dàng để chuyển đổi thông qua các yếu tố.

Chủ Nhật, 1 tháng 3, 2009

Single Dimensional Arrays

Bạn có thể khai báo một mảng một chiều của năm số nguyên như trong ví dụ sau đây:

int[] array = new int[5];

Mảng này chứa các yếu tố từ mảng [0] đến mảng [4]. Toán tử mới được sử dụng để tạo ra các mảng và khởi tạo các phần tử mảng để giá trị mặc định của họ. Trong ví dụ này, tất cả các phần tử mảng được khởi tạo bằng không.

Một mảng mà lưu trữ chuỗi các phần tử có thể được khai báo trong cùng một cách. Ví dụ:

string[] stringArray = new string[6];

Nó có thể khởi tạo một mảng khi khai báo, trong trường hợp này, bộ ghi rõ thứ hạng là không cần thiết vì nó đã được cung cấp bởi số phần tử trong danh sách khởi tạo. Ví dụ:

int[] array1 = new int[] { 1, 3, 5, 7, 9 };

Một mảng chuỗi có thể được khởi tạo trong cùng một cách. Sau đây là một khai báo của một mảng chuỗi trong đó mỗi phần tử mảng được khởi tạo bởi một tên của một ngày:

string[] weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

Khi bạn khởi tạo một mảng khi khai báo, bạn có thể sử dụng các phím tắt sau đây:

int[] array2 = { 1, 3, 5, 7, 9 };
string[] weekDays2 = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

Nó có thể khai báo một biến mảng mà không cần khởi động, nhưng bạn phải sử dụng toán tử mới khi bạn chỉ định một mảng đến biến này. Ví dụ:

int[] array3;
array3 = new int[] { 1, 3, 5, 7, 9 }; // OK
//array3 = {1, 3, 5, 7, 9}; // Error

Xem xét các khái báo mảng sau đây:

SomeType[] array4 = new SomeType[10];

DangTrung.

Truyền các mảng như là tham số

Mảng có thể được thông qua như đối số cho các thông số method. Bởi vì mảng là loại tham chiếu, các method có thể thay đổi giá trị trong các phần tử.

Bạn có thể truyền một mảng một chiều, khởi tạo một phương pháp. Ví dụ, các câu sau đây sẽ gửi một mảng cho một method in ấn.

int[] theArray = { 1, 3, 5, 7, 9 };
PrintArray(theArray);

Các mã sau đây cho thấy một thực hiện một phần của method in ấn.

void PrintArray(int[] arr)
{
      // Method code.
}

Bạn có thể khởi tạo và thông qua một mảng mới trong một bước, như được thể hiện trong ví dụ sau đây.

PrintArray(new int[] { 1, 3, 5, 7, 9 });

Trong ví dụ sau đây, một mảng trong dây được khởi tạo và thông qua như một đối số cho một method PrintArray cho các chuỗi. method này sẽ hiển thị các phần tử trong mảng. Tiếp theo, các phương thức ChangeArray và ChangeArrayElement được gọi cho chứng minh là việc gửi một đối số mảng theo giá trị không ngăn cản các thay đổi cho các phần tử mảng.

class ArrayClass
{
       static void PrintArray(string[] arr)
       {
             for (int i = 0; i < arr.Length; i++)
            {
                   System.Console.Write(arr[i] + "{0}", i < arr.Length - 1 ? " " : "");
            }
            System.Console.WriteLine();
       }
       static void ChangeArray(string[] arr)
       {
              // The following attempt to reverse the array does not persist when
              // the method returns, because arr is a value parameter.
              arr = (arr.Reverse()).ToArray();
              // The following statement displays Sat as the first element in the array.
              System.Console.WriteLine("arr[0] is {0} in ChangeArray.", arr[0]);
        }

        static void ChangeArrayElements(string[] arr)
        {
                // The following assignments change the value of individual array
                // elements.
                arr[0] = "Sat";
                arr[1] = "Fri";
                arr[2] = "Thu";
                // The following statement again displays Sat as the first element
                // in the array arr, inside the called method.
                System.Console.WriteLine("arr[0] is {0} in ChangeArrayElements.", arr[0]);
        }

        static void Main()
        {
                // Declare and initialize an array.
                string[] weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
               // Pass the array as an argument to PrintArray.
               PrintArray(weekDays);

               // ChangeArray tries to change the array by assigning something new
               // to the array in the method.
               ChangeArray(weekDays);

              // Print the array again, to verify that it has not been changed.
              System.Console.WriteLine("Array weekDays after the call to ChangeArray:");
              PrintArray(weekDays);
              System.Console.WriteLine();

              // ChangeArrayElements assigns new values to individual array elements.
              ChangeArrayElements(weekDays);

              // The changes to individual elements persist after the method returns.
              // Print the array, to verify that it has been changed.
              System.Console.WriteLine("Array weekDays after the call to ChangeArrayElements:");
              PrintArray(weekDays);
      }
}
// Output:
// Sun Mon Tue Wed Thu Fri Sat
// arr[0] is Sat in ChangeArray.
// Array weekDays after the call to ChangeArray:
// Sun Mon Tue Wed Thu Fri Sat
//
// arr[0] is Sat in ChangeArrayElements.
// Array weekDays after the call to ChangeArrayElements:
// Sat Fri Thu Wed Thu Fri Sat

Sử dụng foreach với các mảng

C# cũng cung cấp các câu lệnh foreach. Câu lệnh này cung cấp một cách đơn giản, trong sạch cho lặp lại thông qua các phần tử của một mảng. Ví dụ, mã sau đây tạo ra một mảng gọi là con số và duyệt qua nó với câu lệnh foreach:

int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };
foreach (int i in numbers)
{
        System.Console.Write("{0} ", i);
}
// Output: 4 5 6 1 2 3 -2 -1 0

Với mảng đa chiều, bạn có thể sử dụng cùng một phương pháp cho lặp lại thông qua các phần tử, ví dụ:

int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };
// Or use the short form:
// int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)
{
          System.Console.Write("{0} ", i);
}
// Output: 9 99 3 33 5 55

Tuy nhiên, với mảng đa chiều, sử dụng một vòng lặp lồng nhau để giúp bạn kiểm soát nhiều hơn đối với các phần tử mảng.

Mảng không đều (Jagged Arrays)

Một mảng không đều là một mảng mà các các phần tử là các mảng. Các yếu tố của một mảng không đều có thể được các kích thước khác nhau và kích cỡ. Một mảng không đều đôi khi được gọi là một "mảng của các mảng." Các ví dụ sau đây cho thấy làm thế nào cho khai báo, khởi tạo, và các mảng truy cập không đều.

Sau đây là một khai báo của một mảng một chiều là có ba các phần tử, mỗi phần là một mảng một chiều các số nguyên:

int[][] jaggedArray = new int[3][];

Trước khi bạn có thể sử dụng jaggedArray, các phần tử của nó phải được khởi tạo. Bạn có thể khởi tạo các các phần tử như thế này:

jaggedArray[0] = new int[5];
jaggedArray[1] = new int[4];
jaggedArray[2] = new int[2];

Mỗi trong các phần tử là một mảng một chiều các số nguyên. Yếu tố đầu tiên là một mảng trong 5 số nguyên, thứ hai là một mảng của 4 số nguyên, và thứ ba là một mảng của 2 số nguyên.

Nó cũng có thể sử dụng initializers để điền vào các phần tử của mảng có giá trị, trong trường hợp bạn không cần phải có kích thước mảng. Ví dụ:

jaggedArray[0] = new int[] { 1, 3, 5, 7, 9 };
jaggedArray[1] = new int[] { 0, 2, 4, 6 };
jaggedArray[2] = new int[] { 11, 22 };

Bạn cũng có thể khởi tạo mảng khi khai báo như thế này:

int[][] jaggedArray2 = new int[][]
{
        new int[] {1,3,5,7,9},
        new int[] {0,2,4,6},
        new int[] {11,22}
};

Bạn có thể sử dụng hình thức viết tắt sau đây. Chú ý là bạn không thể bỏ qua toán tử mới từ khởi tạo phần tử vì không có khởi tạo mặc định cho các phần tử:

int[][] jaggedArray3 =
{
       new int[] {1,3,5,7,9},
       new int[] {0,2,4,6},
       new int[] {11,22}
};

Một mảng không đều là một mảng trong mảng, và do đó phần tử của nó là loại tham chiếu và được khởi tạo giá trị null.

Bạn có thể truy cập phần tử mảng cá nhân như các ví dụ này:

// Assign 77 to the second element ([1]) of the first array ([0]):
jaggedArray3[0][1] = 77;

// Assign 88 to the second element ([1]) of the third array ([2]):
jaggedArray3[2][1] = 88;

Nó có thể kết hợp các mảng không đều và đa chiều. Sau đây là một khai báo và khởi tạo một mảng một chiều không đều có chứa ba phần tử mảng hai chiều kích thước khác nhau.

int[][,] jaggedArray4 = new int[3][,]
{
       new int[,] { {1,3}, {5,7} },
       new int[,] { {0,2}, {4,6}, {8,10} },
       new int[,] { {11,22}, {99,88}, {0,9} }
};

Bạn có thể truy cập vào phần tử cá nhân như trong ví dụ này, hiển thị giá trị của phần tử [1,0] trong mảng đầu tiên (giá trị 5):

System.Console.Write("{0}", jaggedArray4[0][1, 0]);

Method này trả về độ dài số mảng chứa trong các mảng không đều. Ví dụ, giả sử bạn đã khai báo mảng trước, dòng này:

System.Console.WriteLine(jaggedArray4.Length);

DangTrung.

Mảng đa chiều (Multidimensional Arrays)

Mảng có thể có nhiều hơn một chiều. Ví dụ, việc khai báo sau đây tạo ra một mảng hai chiều của bốn hàng và hai cột.

int[,] array = new int[4, 2];

Việc kê khai sau đây tạo ra một mảng ba chiều, 4, 2, và 3.

int[, ,] array1 = new int[4, 2, 3];

Bạn có thể khởi tạo mảng khi khai báo, như được thể hiện trong ví dụ sau đây.

// Two-dimensional array.
int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// The same array with dimensions specified.
int[,] array2Da = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// A similar array with string elements.
string[,] array2Db = new string[3, 2] { { "one", "two" }, { "three", "four" },{ "five", "six" } };

// Three-dimensional array.
int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },{ { 7, 8, 9 }, { 10, 11, 12 } } };
// The same array with dimensions specified.
int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } },{ { 7, 8, 9 }, { 10, 11, 12 } } };

// Accessing array elements.
System.Console.WriteLine(array2D[0, 0]);
System.Console.WriteLine(array2D[0, 1]);
System.Console.WriteLine(array2D[1, 0]);
System.Console.WriteLine(array2D[1, 1]);
System.Console.WriteLine(array2D[3, 0]);
System.Console.WriteLine(array2Db[1, 0]);
System.Console.WriteLine(array3Da[1, 0, 1]);
System.Console.WriteLine(array3D[1, 1, 2]);

Bạn cũng có thể khởi tạo mảng mà không cần xác định thứ hạng.

int[,] array4 = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };

Nếu bạn chọn cho khai báo một biến mảng mà không cần khởi động, bạn phải sử dụng toán tử mới để phân định một mảng đến biến. Việc sử dụng mới này được thể hiện trong ví dụ sau đây.

int[,] array5;
array5 = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };

Ví dụ sau gán một giá trị cho một phần tử mảng cụ thể.

array5[2, 1] = 25;

Tương tự, ví dụ sau đây nhận được giá trị của một phần tử mảng cụ thể và gán nó cho elementValue biến.

int elementValue = array5[2, 1];

Ví dụ mã sau khởi tạo các các phần tử mảng cho giá trị mặc định (trừ các mảng không đều).

int[,] array6 = new int[10, 10];

DangTrung.

Đối tượng Arrays

Trong C#, mảng là đối tượng thực sự, và không chỉ là vùng địa chỉ bộ nhớ kề nhau như trong C và C++. Array là kiểu cơ sở trừu tượng của tất cả các loại mảng. Bạn có thể sử dụng thuộc tính, và các thành viên lớp kia, mà Array có. Một ví dụ này sẽ sử dụng các tài sản dài để có được chiều dài của một mảng. Các mã sau giao cho chiều dài của dãy số, mà là 5, để một lengthOfNumbers biến được gọi là:

int[] numbers = { 1, 2, 3, 4, 5 };
int lengthOfNumbers = numbers.Length;

Các lớp Array cung cấp nhiều phương pháp hữu ích và thuộc tính để phân loại, tìm kiếm, và các mảng sao chép.

Ví dụ này sử dụng các property Rank để hiển thị con số kích thước của một mảng.

class TestArraysClass
{
     static void Main()
     {
          // Declare and initialize an array:
          int[,] theArray = new int[5, 10];
          System.Console.WriteLine("The array has {0} dimensions.", theArray.Rank);
      }
}
// Output: The array has 2 dimensions.

DangTrung

Thứ Hai, 16 tháng 2, 2009

Làm thế nào để xXử lý ngoại lệ trong biểu thức truy vấn

Nó có thể gọi bất kỳ phương pháp trong bối cảnh của một biểu thức query. Tuy nhiên, chúng tôi khuyên bạn nên tránh gọi bất kỳ method trong một biểu thức query có thể tạo ra một tác dụng phụ chẳng hạn như thay đổi nội dung của nguồn dữ liệu hoặc throw một ngoại lệ. Ví dụ này cho thấy làm thế nào để tránh trường hợp ngoại lệ nâng cao khi bạn gọi phương thức trong một biểu thức query mà không vi phạm nói chung. NET Framework hướng dẫn về xử lý ngoại lệ. Những trạng thái hướng dẫn đó thì có thể bắt một ngoại lệ cụ thể khi bạn hiểu tại sao nó sẽ được ném ra trong một bối cảnh cụ thể.

Ví dụ sau đây cho thấy làm thế nào để di chuyển mã xử lý ngoại lệ bên ngoài một biểu thức query. Điều này chỉ có thể khi các method không phụ thuộc vào bất kỳ các biến local để truy vấn.

class ExceptionsOutsideQuery
{
      static void Main()
      {
            // DO THIS with a datasource that might
            // throw an exception. It is easier to deal with
            // outside of the query expression.
            IEnumerable dataSource;
            try
            {
                    dataSource = GetData();
            }
            catch (InvalidOperationException)
            {
                   // Handle (or don't handle) the exception
                   // in the way that is appropriate for your application.
                   Console.WriteLine("Invalid operation");
                   goto Exit;
            }
            // If we get here, it is safe to proceed.
            var query = from i in dataSource
            select i * i;
            foreach (var i in query)
                   Console.WriteLine(i.ToString());


            //Keep the console window open in debug mode
            Exit:
            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
     }


      // A data source that is very likely to throw an exception!
      static IEnumerable GetData()
      {
            throw new InvalidOperationException();
      }
}

Trong một số trường hợp, câu trả lời tốt nhất để một ngoại lệ được thrown từ bên trong một query có thể để ngăn chặn việc thực hiện query ngay lập tức. Ví dụ sau đây cho thấy làm thế nào để xử lý các trường hợp ngoại lệ có thể được thrown từ bên trong một thân query. Giả sử rằng SomeMethodThatMightThrow khả năng có thể gây ra một ngoại lệ đòi hỏi phải thực hiện query để ngăn chặn.

Lưu ý rằng khối try bao bọc các vòng lặp foreach, và không phải là query chính nó. Điều này là do các vòng lặp foreach là điểm mà tại đó các truy vấn được thực thi.

class QueryThatThrows
{
        static void Main()
        {
                // Data source.
                string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };


                // Demonstration query that throws.
                var exceptionDemoQuery = from file in files
                       let n = SomeMethodThatMightThrow(file)
                       select n;


               // Runtime exceptions are thrown when query is executed.
               // Therefore they must be handled in the foreach loop.
               try
               {
                      foreach (var item in exceptionDemoQuery)
                      {
                              Console.WriteLine("Processing {0}", item);
                      }
                }


                // Catch whatever exception you expect to raise
                // and/or do any necessary cleanup in a finally block
                catch (InvalidOperationException e)
               {
                      Console.WriteLine(e.Message);
               }


               //Keep the console window open in debug mode
               Console.WriteLine("Press any key to exit");
               Console.ReadKey();
        }


         // Not very useful as a general purpose method.
         static string SomeMethodThatMightThrow(string s)
         {
               if (s[4] == 'C')
                     throw new InvalidOperationException();
               return @"C:\newFolder\" + s;
         }
}
/* Output:
Processing C:\newFolder\fileA.txt
Processing C:\newFolder\fileB.txt
Operation is not valid due to the current state of the object.
*/

DangTrung.

Làm thế nào để xử lý giá trị Null trong biểu thức truy vấn

Ví dụ này cho thấy làm thế nào để xử lý các giá trị null có thể có trong bộ sưu tập nguồn. Một bộ sưu tập các đối tượng đó như là một IEnumerable có thể chứa các yếu tố có giá trị null. Nếu nguồn là một bộ sưu tập vô giá trị hoặc có một phần tử có giá trị null, và query của bạn không xử lý các giá trị null, NullReferenceException sẽ được đẩy ra ngoài khi bạn thực hiện câu truy vấn.

Bạn có thể bảo vệ mã để tránh một ngoại lệ tham chiếu null như trong ví dụ sau đây:

var query1 =  from c in categories
       where c != null
       join p in products on c.ID equals
               (p == null ? null : p.CategoryID)
       select new { Category = c.Name, Name = p.Name };

Trong ví dụ trước, các nơi mệnh đề lọc ra tất cả các yếu tố null trong thứ tự danh mục. Kỹ thuật này được độc lập của việc kiểm tra null trong mệnh đề join. Các biểu thức điều kiện với null trong ví dụ này hoạt động bởi vì Products.CategoryID là kiểu int? đó là viết tắt cho Nullable.

Trong một mệnh đề join, nếu chỉ có một trong các phím so sánh là một loại giá trị nullable, bạn có thể bỏ các kia với một loại nullable trong biểu thức query. Trong ví dụ sau đây, giả sử là EmployeeID là một cột chứa giá trị kiểu int?:

void TestMethod(Northwind db)
{
       var query = from o in db.Orders
              join e in db.Employees
                     on o.EmployeeID equals (int?)e.EmployeeID
              select new { o.OrderID, e.FirstName };
}

DangTrung.

Làm thế nào để join bằng cách sử dụng Key Composite

Ví dụ này cho thấy làm thế nào để thực hiện join các hoạt động mà bạn muốn sử dụng nhiều hơn một khóa chính để xác định một trận đấu. Điều này được thực hiện bằng cách sử dụng một khóa composite. Bạn tạo một khóa composite như là một loại anonymous hoặc tên gõ với các giá trị mà bạn muốn so sánh. Nếu biến query sẽ được chuyển qua các biên giới, phương pháp sử dụng một loại có tên overrides Equals và GetHashCode cho khoá. Tên của các thuộc tính, và thứ tự mà chúng xảy ra, phải được giống hệt nhau trong mỗi khóa.

Ví dụ sau đây cho thấy làm thế nào để sử dụng một khóa composite để join dữ liệu từ ba bảng:

var query = from o in db.Orders from p in db.Products
       join d in db.OrderDetails on new {o.OrderID, p.ProductID} equals new {d.OrderID,
              d.ProductID} into details from d in details
       select new {o.OrderID, p.ProductID, d.UnitPrice};

Các khóa composite phụ thuộc vào tên của các thuộc tính trong các khóa, và thứ tự mà chúng xảy ra. Nếu các thuộc tính trong chuỗi nguồn không có tên giống nhau, bạn phải gán tên mới trong các khóa. Ví dụ, nếu bảng Orders và bảng OrderDetails từng được sử dụng tên khác nhau cho các cột của họ, bạn có thể tạo ra phím composite bằng cách chỉ định tên giống hệt nhau trong các loại anonymous:

join...on new {Name = o.CustomerName, ID = o.CustID} equals
        new {Name = d.CustName, ID = d.CustID }

DangTrung.

Chủ Nhật, 15 tháng 2, 2009

Làm thế nào để sắp xếp các kết quả của một Clause join

Ví dụ này cho thấy làm thế nào để sắp xếp các kết quả của một hoạt động join. Lưu ý rằng các lệnh được thực hiện sau khi join. Mặc dù bạn có thể sử dụng một mệnh đề orderby với một hoặc nhiều trình tự mã nguồn trước khi join, nhìn chung chúng takhông giới thiệu nó. Một số nhà cung cấp LINQ có thể không có duy trì lệnh sau khi join.

Truy vấn này tạo ra một group join, và sau đó sắp xếp các group dựa trên các yếu tố thể loại, mà vẫn còn trong phạm vi. Bên trong bộ khởi tạo kiểu anonymous, một sub query orhers tất cả các yếu tố kết hợp từ các chuỗi sản phẩm.

class HowToOrderJoins
{
       #region Data
       class Product
       {
              public string Name { get; set; }
              public int CategoryID { get; set; }
       }

       class Category
       {
              public string Name { get; set; }
              public int ID { get; set; }
       }

       // Specify the first data source.
       List categories = new List()
       {
               new Category(){Name="Beverages", ID=001},
               new Category(){ Name="Condiments", ID=002},
               new Category(){ Name="Vegetables", ID=003},
               new Category() { Name="Grains", ID=004},
               new Category() { Name="Fruit", ID=005}
       };

       // Specify the second data source.
       List products = new List()
       {
               new Product{Name="Cola", CategoryID=001},
               new Product{Name="Tea", CategoryID=001},
               new Product{Name="Mustard", CategoryID=002},
               new Product{Name="Pickles", CategoryID=002},
               new Product{Name="Carrots", CategoryID=003},
               new Product{Name="Bok Choy", CategoryID=003},
               new Product{Name="Peaches", CategoryID=005},
               new Product{Name="Melons", CategoryID=005},
       };
       #endregion
       
       static void Main()
       {
               HowToOrderJoins app = new HowToOrderJoins();
               app.OrderJoin1();

               // Keep console window open in debug mode.
               Console.WriteLine("Press any key to exit.");
               Console.ReadKey();
        }

        void OrderJoin1()
        {
                var groupJoinQuery2 =  from category in categories
                       join prod in products on category.ID equals prod.CategoryID into prodGroup
                       orderby category.Name
                       select new
                       {
                               Category = category.Name,
                               Products = from prod2 in prodGroup  orderby prod2.Name
                               select prod2
                       };
                foreach (var productGroup in groupJoinQuery2)
                {
                        Console.WriteLine(productGroup.Category);
                        foreach (var prodItem in productGroup.Products)
                        {
                                Console.WriteLine(" {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
                         }
                 }
         }
        /* Output :
            Beverages
            Cola 1
            Tea 1
            Condiments
            Mustard 2
            Pickles 2
            Fruit
            Melons 5
            Peaches 5
            Grains
            Vegetables
            Bok Choy 3
            Carrots 3
         */
}
DangTrung.

Làm thế nào để sử dụng Left Outer Joins

Một left outer join là một join, trong đó mỗi phần tử của các bộ sưu tập đầu tiên được trả về, bất kể nó có bất kỳ yếu tố tương quan trong bộ sưu tập thứ hai. Bạn có thể sử dụng LINQ để thực hiện một left outer join bằng cách gọi DefaultIfEmpty kết quả của một group join.

Ví dụ sau đây cho thấy làm thế nào để sử dụng Methos DefaultIfEmpty kết quả của một group join để thực hiện một left outer join.

Bước đầu tiên trong việc tạo ra một left outer join trong hai bộ sưu tập là để thực hiện một bên join bằng cách sử dụng một group join. Trong ví dụ này, danh sách các đối tượng Person inner join vào danh sách các đối tượng PET dựa trên một Person object phù hợp với Pet.Owner.

Bước thứ hai là để bao gồm mỗi yếu tố của bộ sưu tập (left) đầu tiên trong tập hợp kết quả ngay cả khi không có yếu tố phù hợp trong bộ sưu tập phải. Điều này được thực hiện bằng cách gọi DefaultIfEmpty trên mỗi chuỗi kết hợp các yếu tố từ các group join. Trong ví dụ này, DefaultIfEmpty được gọi vào mỗi chuỗi các đối tượng phù hợp với PET. Nó trả về một bộ sưu tập có chứa một giá trị, mặc định duy nhất nếu các trình tự của các đối tượng phù hợp PET trống cho bất kỳ đối tượng Person, qua đó đảm bảo rằng kết quả mỗi đối tượng Person được đại diện trong bộ sưu tập.

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

class Pet
{
       public string Name { get; set; }
       public Person Owner { get; set; }
}

public static void LeftOuterJoinExample()
{
       Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
       Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
       Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
       Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

       Pet barley = new Pet { Name = "Barley", Owner = terry };
       Pet boots = new Pet { Name = "Boots", Owner = terry };
       Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
       Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
       Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

       // Create two lists.
       List people = new List { magnus, terry, charlotte, arlene };
       List pets = new List { barley, boots, whiskers, bluemoon, daisy };

       var query = from person in people
              join pet in pets on person equals pet.Owner into gj
              from subpet in gj.DefaultIfEmpty()
              select new { 
                      person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name)      
              };

       foreach (var v in query)
       {
              Console.WriteLine("{0,-15}{1}", v.FirstName + ":", v.PetName);
       }
}

// This code produces the following output:
//
// Magnus: --- > Daisy
// Terry: --- > Barley
// Terry: --- >  Boots
// Terry: --- > Blue Moon
// Charlotte: --- > Whiskers
// Arlene: --- >
DangTrung

Làm thế nào để thực hiện Grouped Join

Các group join rất hữu ích cho tạo ra các cấu trúc phân cấp dữ liệu. Những cặp này mỗi yếu tố từ các bộ sưu tập đầu tiên với một tập hợp các yếu tố tương quan từ các bộ sưu tập thứ hai.

Ví dụ, một class hoặc cơ sở dữ liệu một bảng quan hệ có tên là Sinh viên có thể chứa hai lĩnh vực: Id và Name. Một class thứ hai hoặc bảng cơ sở dữ liệu quan hệ có tên là khóa học có thể có hai lĩnh vực: StudentId và CourseTitle. Một nhóm tham gia của hai nguồn dữ liệu, dựa trên kết hợp Student.Id và Course.StudentId, sẽ từng nhóm sinh viên với một bộ sưu tập của các đối tượng học.

Ví dụ đầu tiên trong chủ đề này cho bạn thấy làm thế nào để thực hiện một group join. Ví dụ thứ hai chỉ cho bạn cách sử dụng một nhóm join để tạo ra các phần tử XML.

Ví dụ Group Join :

Ví dụ sau đây thực hiện một nhóm join của các đối tượng của loại hình Person và PET dựa trên những người phù hợp với property Pet.Owner. Không giống như một group không join, mà sẽ tạo ra một cặp của các yếu tố cho mỗi trận đấu, các group join tạo ra chỉ có một kết quả là đối tượng cho từng thành phần của bộ sưu tập đầu tiên, mà trong ví dụ này là một đối tượng Person. Các yếu tố tương ứng từ các bộ sưu tập thứ hai, trong ví dụ này là Pet đối tượng, được nhóm lại thành một bộ sưu tập. Cuối cùng, chức năng kết quả chọn tạo ra một loại giấu tên cho mỗi trận đấu mà bao gồm Person.FirstName và một bộ sưu tập của các đối tượng Pet.

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

class Pet
{
        public string Name { get; set; }
        public Person Owner { get; set; }
}

///
/// This example performs a grouped join.
///
public static void GroupJoinExample()
{
        Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
        Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
        Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
        Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

        Pet barley = new Pet { Name = "Barley", Owner = terry };
        Pet boots = new Pet { Name = "Boots", Owner = terry };
        Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
        Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
        Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

        // Create two lists.
        List people = new List { magnus, terry, charlotte, arlene };
        List pets = new List { barley, boots, whiskers, bluemoon, daisy };

        // Create a list where each element is an anonymous type
        // that contains the person's first name and a collection of
        // pets that are owned by them.
        var query = from person in people
                 join pet in pets on person equals pet.Owner into gj
                 select new { OwnerName = person.FirstName, Pets = gj };

        foreach (var v in query)
        {
               // Output the owner's name.
              Console.WriteLine("{0}:", v.OwnerName);
              // Output each of the owner's pet's names.
              foreach (Pet pet in v.Pets)
                    Console.WriteLine(" {0}", pet.Name);
        }
}
Group join rất lý tưởng cho việc tạo ra XML bằng cách sử dụng LINQ to XML. Ví dụ sau là tương tự như ví dụ trước, ngoại trừ thay vì tạo ra các loại giấu tên, chức năng chọn kết quả tạo ra các phần tử XML mà đại diện cho các đối tượng tham gia.

Bạn chỉ cần thay đổi dòng dưới cho ví dụ ở trên.

// Create XML to display the hierarchical organization of people and their pets.
XElement ownersAndPets = new XElement("PetOwners",
       from person in people join pet in pets on person equals pet.Owner into gj
                select new XElement("Person",
                        new XAttribute("FirstName", person.FirstName),
                        new XAttribute("LastName", person.LastName),
                        from subpet in gj
                            select new XElement("Pet", subpet.Name)));


Console.WriteLine(ownersAndPets);

DangTrung.

Thứ Bảy, 14 tháng 2, 2009

Làm thế nào nhóm Kết quả của contiguous keys

Ví dụ sau đây cho thấy làm thế nào để các nguyên tố nhóm thành nhiều phần đại diện cho subsequences của các contiguous keys. Ví dụ, giả sử rằng bạn có các trình tự sau đây của các cặp khóa có giá trị:
  • Key : A, A, A, B, C, A, B, B
  • Value : We, think, that, Linq, is, really, cool, !

Các nhóm sau đây sẽ được tạo ra theo thứ tự này:
  1. We, think, that
  2. Linq
  3. is
  4. really
  5. cool, !
Giải pháp này được thực hiện như là một phương pháp mở rộng đó là thread an toàn và trả về kết quả của nó một cách trực tuyến. Nói cách khác, nó tạo ra nhóm của nó khi nó di chuyển qua các dãy nguồn. Không giống như các nhà điều hành nhóm hay orderby, nó có thể bắt đầu trở lại nhóm người gọi trước khi tất cả các trình tự đã được đọc.

Chủ đề an toàn được thực hiện bằng cách làm một bản sao của từng nhóm hoặc từng đoạn theo trình tự được lặp lại nguồn, như được giải thích trong các ý kiến mã nguồn. Nếu dãy nguồn có một chuỗi lớn các mục liên tiếp, ngôn ngữ chung có thể bỏ một OutOfMemoryException.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ChunkIt
{
      // Static class to contain the extension methods.
      public static class MyExtensions
      {
              public static IEnumerable> ChunkBy(this  
                         IEnumerable source, Func keySelector)
              {
                      return source.ChunkBy(keySelector, EqualityComparer.Default);
              }

              public static IEnumerable> ChunkBy(this 
                         IEnumerable source, Func keySelector, 
                         IEqualityComparer comparer)
             {
                        // Flag to signal end of source sequence.
                        const bool noMoreSourceElements = true;

                        // Auto-generated iterator for the source array.
                        var enumerator = source.GetEnumerator();

                        // Move to the first element in the source sequence.
                        if (!enumerator.MoveNext()) yield break;

                        Chunk current = null;
                        while (true)
                        {
                               // Get the key for the current Chunk. The source iterator will churn through
                               // the source sequence until it finds an element with a key that doesn't match.
                               var key = keySelector(enumerator.Current);

                               // Make a new Chunk (group) object that initially has one 
                               // GroupItem, which is a copy of the current source element.
                               current = new Chunk(key, enumerator, value => 
                                               comparer.Equals(key, keySelector(value)));                              
                               yield return current;
                               if (current.CopyAllChunkElements() == noMoreSourceElements)
                               {
                                        yield break;
                               }
                       }
               }

               class Chunk : IGrouping
               {                       
                       // has a reference to the next ChunkItem in the list.
                       class ChunkItem
                       {
                                public ChunkItem(TSource value)
                                {
                                         Value = value;
                                }
                                public readonly TSource Value;
                                public ChunkItem Next = null;
                       }
                       // The value that is used to determine matching elements
                       private readonly TKey key;

                       // Stores a reference to the enumerator for the source sequence
                       private IEnumerator enumerator;

                       // A reference to the predicate that is used to compare keys.
                       private Func predicate;

                      // Stores the contents of the first source element that belongs with this chunk.
                      private readonly ChunkItem head;

                     // End of the list. It is repositioned each time a new. ChunkItem is added.
                     private ChunkItem tail;

                     // Flag to indicate the source iterator has reached the end of the source sequence.
                     internal bool isLastSourceElement = false;

                     // Private object for thread syncronization
                     private object m_Lock;

                    // REQUIRES: enumerator != null && predicate != null
                    public Chunk(TKey key, IEnumerator enumerator, 
                            Func predicate)
                    {
                            this.key = key;
                            this.enumerator = enumerator;
                            this.predicate = predicate;

                            // A Chunk always contains at least one element.
                            head = new ChunkItem(enumerator.Current);

                           // The end and beginning are the same until the list contains > 1 elements.
                           tail = head;

                           m_Lock = new object();
                    }

                   // Indicates that all chunk elements have been copied to the list of ChunkItems,
                   // and the source enumerator is either at the end, or else on an element with a new key.
                   // the tail of the linked list is set to null in the CopyNextChunkElement method if the
                  // key of the next element does not match the current chunk's key, or there are no more  
                  // elements in the source.
                  private bool DoneCopyingChunk { get { return tail == null; } }

                 // Adds one ChunkItem to the current group 
                 // REQUIRES: !DoneCopyingChunk && lock(this)
                 private void CopyNextChunkElement()
                 {
                         // Try to advance the iterator on the source sequence.
                         // If MoveNext returns false we are at the end, 
                         // and isLastSourceElement is set to true
                         isLastSourceElement = !enumerator.MoveNext();

                         // If we are (a) at the end of the source, or (b) at the end of the current chunk
                         // then null out the enumerator and predicate for reuse with the next chunk.
                         if (isLastSourceElement || !predicate(enumerator.Current))
                         {
                                 enumerator = null;
                                 predicate = null;
                         }
                         else
                         {
                                  tail.Next = new ChunkItem(enumerator.Current);
                         }

                        // tail will be null if we are at the end of the chunk elements
                        // This check is made in DoneCopyingChunk.
                        tail = tail.Next;
               }
               internal bool CopyAllChunkElements()
               {
                       while (true)
               {
               lock (m_Lock)
               {
                     if (DoneCopyingChunk)
                     {
                              // If isLastSourceElement is false,  it signals to the 
                              // outer iterator  to continue iterating.
                              return isLastSourceElement;
                     }
                     else
                     {
                             CopyNextChunkElement();
                      }
              }
       }
}


public TKey Key { get { return key; } }

// Invoked by the inner foreach loop. This method stays just one step ahead
// of the client requests. It adds the next element of the chunk only after
// the clients requests the last element in the list so far.
public IEnumerator GetEnumerator()
{
         //Specify the initial element to enumerate.
         ChunkItem current = head;

         // There should always be at least one ChunkItem in a Chunk.
               while (current != null)
              {
                       // Yield the current item in the list.
                       yield return current.Value;

                       // Copy the next item from the source sequence,
                       // if we are at the end of our local list.
                       lock (m_Lock)
                       {
                              if (current == tail)
                              {
                                      CopyNextChunkElement();
                              }
                       }
                       // Move to the next ChunkItem in the list.
                       current = current.Next;
                 }
           }

           System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
           {
                  return GetEnumerator();
           }
      }
}

       // A simple named type is used for easier viewing in the debugger. Anonymous types
       // work just as well with the ChunkBy operator.
       public class KeyValPair
       {
              public string Key { get; set; }
              public string Value { get; set; }
       }

       class Program
       {
              // The source sequence.
              public static IEnumerable list;

              // Query variable declared as class member to be available
              // on different threads.
              static IEnumerable> query;

              static void Main(string[] args)
              {
                    // Initialize the source sequence with an array initializer.
                    list = new[]
                    {
                          new KeyValPair{ Key = "A", Value = "We" },
                          new KeyValPair{ Key = "A", Value = "Think" },
                          new KeyValPair{ Key = "A", Value = "That" },
                          new KeyValPair{ Key = "B", Value = "Linq" },
                          new KeyValPair{ Key = "C", Value = "Is" },
                          new KeyValPair{ Key = "A", Value = "Really" },
                          new KeyValPair{ Key = "B", Value = "Cool" },
                          new KeyValPair{ Key = "B", Value = "!" }
                    };
                    // Create the query by using our user-defined query operator.
                    query = list.ChunkBy(p => p.Key);
                    // ChunkBy returns IGrouping objects, therefore a nested
                    // foreach loop is required to access the elements in each "chunk".
                    foreach (var item in query)
                    {
                          Console.WriteLine("Group key = {0}", item.Key);
                          foreach (var inner in item)
                          {
                                 Console.WriteLine("\t{0}", inner.Value);
                          }
                    }
                    Console.WriteLine("Press any key to exit");
                    Console.ReadKey();
              } 
       }
}

Để sử dụng Methos mở rộng trong dự án của bạn, sao chép các MyExtensions class Static vào một tập tin mã nguồn mới hoặc hiện tại và nếu nó là cần thiết, thêm một chỉ thị bằng cách sử dụng cho các namespace nơi mà nó được đặt.

 DangTrung.