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<T> 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<int>.

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 };
}

 

 

Làm Thế Nào Config Log4Net Trong C#

Log4net là gì?

Log4net là một công cụ giúp người lập trình ghi lại những thông tin trong lúc chạy ứng dụng. Nó chính là một phiên bản chuyển thể từ log4j và vẫn tiếp tục được phát triển kể từ năm 2001. Trong trường hợp ứng dụng của bạn có lỗi mà vẫn không tìm được nguyên nhân, log4net có thể là vị cứu tinh để giúp bạn xác định nơi gây lỗi. Ngoài ra, Log4net còn có thể thay đổi trạng thái log lúc chương trình chạy mà không cần ngừng chương trình. Bên cạnh đó, khi sử dụng log4net sẽ không ảnh hưởng đáng kể đến performance của ứng dụng, log4net còn được thiết kế với tính flexibility rất cao, chúng ta có thể mở rộng và thêm thắt những thứ mình muốn vào thư viện log4net, chẳng hạn như cách thức log, định dạng log,

Sử dụng như thế nào?

Trong bài viết này, tôi sẽ giới thiệu cách sử dụng log4net cho một window application và cách config cho log4net ghi thông tin log ra file bằng một file config. Thực ra đối với web application thì cách sử dụng hoàn toàn tương tự. Chỉ có một số trường hợp file log của bạn không sinh ra được vì không đủ quyền. Như các bạn biết thì Web application chạy dưới 1 process bằng quyền của user ASPNET trong Windows, dó đó nếu user này không đủ quyền ghi file vào folder web của bạn thì file log tương ứng cũng có thể không được tạo ra.

Hãy download version mới nhất của log4net từ website apache. và add reference vào project của bạn như hình sau:

Sau khi bạn đã reference Log4net vào project của mình hoàn chỉnh, các bước còn lại bạn tiếp tục config để project của bạn hiểu Log4Net ở đâu. Để project hiểu bạn cần config code mỗi khi project gọi Log4Net, như vậy thì rất dài dòng và phức tạp vì phải gọi đi gọi lại nhiều lần. Cách đơn giản hãy tạo một class dùng chung và bạn có thể gọi bất cứ đâu mà bạn muốn :

public static class LogService
{
      #region Members
      private static readonly ILog logger = LogManager.GetLogger(typeof(LogService));
     #endregion
      #region Constructors
      static LogService()
     {
          BasicConfigurator.Configure();
          XmlConfigurator.Configure();
     }
     #endregion
     #region Methods   
    public static void WriteLog(LogLevel logLevel, String log)
    {
         if (logLevel.Equals(LogLevel.DEBUG))
             logger.Debug(log);
        else if (logLevel.Equals(LogLevel.ERROR))
            logger.Error(log);
        else if (logLevel.Equals(LogLevel.FATAL))
            logger.Fatal(log);
        else if (logLevel.Equals(LogLevel.INFO))
            logger.Info(log);
        else if (logLevel.Equals(LogLevel.WARN))
            logger.Warn(log);
    }
    #endregion
}

Bây giờ chúng ta đã có class dùng chung trong project của bạn, câu hỏi ở đây là chúng ta sẽ gọi chúng như thế nào? và còn config nào nữa ?. Câu trả lời cho các bạn là còn rất nhiều bạn cứ từ từ và xem tiếp theo. Trước tiên bạn xem project của bạn thuộc một thể loại nào Application hay Web, không sao dù là project nào thì đều có file config riêng cho nó.

Application thì ta có App.config

Web thì ta có Web.config.

Bạn hãy thêm config này vào trong config file của bạn :

Trong file cấu hình này, tôi sử dụng RollingFileAppender. Có rất nhiều loại Appender được xây dựng sẵn trong thư viện log4net. Mỗi loại sẽ có công dụng ghi nội dung log vào một nơi khác nhau. Trong đó RollingFileAppender là được sử dụng nhiều nhất và cũng dễ sử dụng nhất. Tôi sẽ giải thích những gì tôi nghĩ là khó hiểu nhất

<file value="Log4netSampleLog.txt">

Thông tin log của chúng ta sẽ được ghi vào file Log4netSampleLog.txt, file này sẽ nằm ở thư mục chạy của ứng dụng, cùng cấp với file exe và file .config của chúng ta. Nếu muốn nó lưu file vào chỗ khác chúng ta có thể hardcode đường dẫn ở đây.

<maxsizerollbackups value="3" />

Dữ liệu log sẽ được ghi vào file, vì ta đang sử dụng là RollingFileAppender, nên khi kích thước file vượt quá một mức nào đó thì nó sẽ đổi tên file cũ và ghi vào file mới. Tổng số lượng file tối đa sẽ là 10 và những file cũ nhất sẽ bị xóa nếu số lượng file vượt quá 3.

<maximumfilesize value="1MB">

Kích thước file log tối đa sẽ là 1MB.

Layout: Đây là phần khá thú vị, những text log mà chúng ta ghi ra sẽ kèm thêm một số thông tin theo như phần định dạng trong layout như ngày tháng, threadId, className, ... Các bạn có thể tùy biến phần layout này để được log output dễ nhìn nhất.

<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
<layout>

Level: Level mặc định sẽ là Debug cho mọi nơi có sử dụng log trong chương trình của bạn. Nghĩa là nếu bạn khai báo như hình, thì mọi chỗ bạn log đều được ghi xuống file vì level DEBUG là level thấp nhất, nhưng nếu chỗ này bạn để là ERROR thì chỉ có những log với level cao hơn hoặc bằng ERROR mới được ghi xuống file. Khi deploy chương trình cho khách hàng, thường thì chúng ta sẽ để level default là ERROR, khi sử dụng có lỗi ta sẽ yêu cầu khách hàng sử lại thành DEBUG nếu cần thiết.

<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>

- Thông thường người ta sử dụng full name của class (kèm theo đầy đủ namespace) để dùng như loggerName. Cách dùng này rất hợp lý vì chúng ta sẽ biết đoạn log của mình sinh ra từ class.nào. Để ghi Log bạn cần phải xác định rằng bạn ghi cái gì và ghi như thế nào?

Để ghi thông tin bạn làm như sau:

Để ghi lỗi bạn làm như sau :

Còn nhiều và nhiều cách config cho Log4Net bạn có thể tham khao các cách config tại trang wen của nó. 

Chúc bạn thành công.

Delegate và Event trong Csharp

Khái niệm delegate được hiểu như là một con trỏ hàm (method). Thực tế là một method nó cũng có 1 vùng nhớ xác định trên Ram và khi biết được địa chỉ của vùng nhớ này thì mình có thể gọi method thực hiện, bình thường mình gọi method thông qua đối tượng (instance) hoặc tên class (nếu là method static) và tên method. Như vậy một delegate được hiểu nôm na là một kiểu dùng để lưu trữ 1 hay nhiều địa chỉ method mà những method này phải cùng prototype (gồm kiểu trả về và danh sách các tham số). Khi ta có một biến delegate đang nắm giữ danh sách các method (có cùng prototype với nó) thì chỉ cần khởi động biến này tất cả các danh sách method đó sẽ được thực hiện lần lượt mà ta không cần quan tâm đến tên method đó nữa.

Delegate rất có ý nghĩa khi kết hợp với event, như bác sangcn đã đề cập thì event là một thể hiện đặc biệt của delegate. Theo khái niệm thì event là một thông điệp được gửi tới những đối tượng đã đăng ký trước đó để thực hiện hành động nào đó kèm theo khi thông điệp đó được gửi tới (nghĩa là sự kiện đó xảy ra). Ví dụ, khi chúng ta click chuột vào 1 nút (button) nào đó trên một form (cửa sổ ứng dụng), nghĩa là lúc này đối tượng nút sẽ truyền một thông điệp (phát ra sự kiện nhấn chuột) cho đối tượng form để gọi tới method mà form này đã đăng ký nhận thông điệp khi sự kiện nhấn chuột xảy ra.

Một ứng dụng cụ thể để hiểu mục đích sử dụng delegate event đó là chúng ta viết một class clock (đồng hồ), và một yêu cầu rằng khi người ta sử dụng đối tượng clock này thì muốn nhận một thông điệp (sự kiện) EndTime (hết giờ) để thực hiện một hành động gì đó kèm theo sự kiện này. Ví dụ ta viết một chương trình game đoán chữ và có giới hạn thời gian cho người chơi là 10 giây, hết thời gian này thì chương trình sẽ thông báo "Time over" chẳng hạn. Như vậy, ta sẽ cần ít nhất 2 class là Game và Clock. Chúng ta hãy xem mã nguồn để thể hiện ví dụ này.

public class Clock
{
    private int _second;
    // Định nghĩa một delegate để trỏ vào những method có kiểu không đối số, không kiểu trả về
    public delegate void TimeOver();
    // Khai báo 1 event thuộc kiểu delegate trên
    public event TimeOver EndTime;
    public Clock(int second)
    {
        _second = second;
    }
    public int Second
    {
        get { return _second; }
        set { _second = value; }
    }
    /// 
    /// Method đếm lùi thời gian cho đến khi _second = 0 thì kết thúc và báo lên sự kiện EndTime
    /// 
    public void Timedown()
    {
        do
        {
            _second--;
            Thread.Sleep(1000);
        }
        while (_second > 0);
        // trước khi gọi event hoặc delegate thì cần kiểm tra biến có null không (nghĩa là có chứa địa chỉ
        // của method nào không) nếu khác null (có chứa 1 ít nhât 1 method) thì mới gọi.
        if (EndTime != null)
            EndTime(); // gọi thực hiện các method đã đăng ký sự kiện.
    }
}
class Game
{
    /// 
    /// Method dùng để thực hiện hành động kèm theo khi sự kiện EndTime (delegate TimeOver) xảy ra
    /// 
    public void GameOver()
    {
        Console.WriteLine("Game over");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Clock c = new Clock(10);
        Game g = new Game();
        // Đăng ký method thực hiện hành động kèm theo khi có sự kiện EndTime xảy ra
        c.EndTime += new Clock.TimeOver(g.GameOver);
        ThreadStart ts = new ThreadStart(c.Timedown);
        Thread ChildThread = new Thread(ts);
        ChildThread.Start();
        Console.WriteLine("Waiting about 10 second...");
    }
}

Chủ đề này là một chủ đề lớn và rất hay vì thế sẽ có video để chúng ta tìm hiểu sâu hơn nữa. Hy vọng bạn cũng phần nào nắm được. Tôi gửi link download mã nguồn cho ví dụ trên để bạn tiện tham khảo.

DemoEvent.rar (23,46 kb)

Nguồn: http://www.hoctinhoctructuyen.com/Questions?page=3&TypeSearch=-1

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
*/

 

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 };
}