雨中的阳光Seattle

靠着很近的Redmond

[转]Lambda Expressions in C# 3.0 – A little Extension Methods and LINQ Too… 2007年09月20日

Filed under: C# — systembug @ 6:23 上午
del.icio.us Tags:

 

正在看有关Lambda表达式的相关文章,简明扼要的介绍了Lambda表达式。

 

 

Lambda Expressions in C# 3.0 – A little Extension Methods and LINQ Too…

by David Hayden

I spent some time with Lambda Expressions in C# 3.0 last night, and they are extremely cool. I haven’t played with Expression Trees yet, which sound like the coolest part of Lambda Expressions, but still, Lambda Expressions are cool just to help ease the burden of writing verbose Anonymous Methods.

Anonymous Methods

I love Anonymous Methods in C# 2.0. The idea behind anonymous methods it to write methods inline to the code so you don’t have to go through the trouble of declaring a formal named method. They are mainly used for small methods that don’t require any need for reuse.

Instead of declaring a separate method IsAbe to find Abe in a list of strings:

class Program
{
    static void Main(string[] args)
    {                    
        List<string> names = new List<string>();
        names.Add("Dave");
        names.Add("John");
        names.Add("Abe");
        names.Add("Barney");
        names.Add("Chuck");

        string abe = names.Find(IsAbe);
        Console.WriteLine(abe);
    }

    public static bool IsAbe(string name)
    {
        return name.Equals("Abe");
    }
}

You can declare an anonymous method inline to save you the trouble:

class Program
{
    static void Main(string[] args)
    {                    
        List<string> names = new List<string>();
        names.Add("Dave");
        names.Add("John");
        names.Add("Abe");
        names.Add("Barney");
        names.Add("Chuck");

        string abe = names.Find(delegate(string name)
                        {
                            return name.Equals("Abe");
                        });

        Console.WriteLine(abe);
    }
}

It can get a lot fancier than that, but that is basically the gist. Declare the method inline to the code for easy stuff not needing reuse, because it saves some typing and puts the method closer to where it is being used which helps with maintenance.

Lambda Expressions

Lambda Expressions make things even easier by allowing you to avoid the anonymous method and that annoying statement block:

class Program
{
    static void Main(string[] args)
    {                    
        List<string> names = new List<string>();
        names.Add("Dave");
        names.Add("John");
        names.Add("Abe");
        names.Add("Barney");
        names.Add("Chuck");

        string abe = names.Find((string name) => name.Equals("Abe"));

        Console.WriteLine(abe);
    }
}

Because Lambda Expressions are smart enough to infer variable types, I don’t even have to explicity mention that name is a string above. I can remove it for even more simplicity and write it as such:

class Program
{
    static void Main(string[] args)
    {                    
        List<string> names = new List<string>();
        names.Add("Dave");
        names.Add("John");
        names.Add("Abe");
        names.Add("Barney");
        names.Add("Chuck");

        string abe = names.Find(name => name.Equals("Abe"));

        Console.WriteLine(abe);
    }
}

Now there is no particular reason why I have to use name as my variable. Often developers will use 1 character variable names in Lambda Expressions just to keep things short. Here we replace name with p and all works the same.

class Program
{
    static void Main(string[] args)
    {                    
        List<string> names = new List<string>();
        names.Add("Dave");
        names.Add("John");
        names.Add("Abe");
        names.Add("Barney");
        names.Add("Chuck");

        string abe = names.Find(p => p.Equals("Abe"));

        Console.WriteLine(abe);
    }
}

Using a Customer Class

I used a list of strings above, but you can just as easily use a list of objects to do the same thing. I will take an abbreviated form of a Customer Class:

public class Customer
{
    public int Id;
    public string Name;
    public string City;

    public Customer(int id, string name, string city)
    {
        Id = id;
        Name = name;
        City = city;
    }
}

 and now use Lambda Expressions to find a particular Customer with a name of “Abe”.

class Program
{
    static void Main(string[] args)
    {            
        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer(1,"Dave","Sarasota"));
        customers.Add(new Customer(2,"John","Tampa"));
        customers.Add(new Customer(3,"Abe","Miami"));

        Customer abe = customers.Find(c => c.Name.Equals("Abe"));
    }
}

Again, we could make things more obvious by explicity saying that c is of type Customer, but I wouldn’t bet on many people doing it 🙂 You could write the above as follows:

class Program
{
    static void Main(string[] args)
    {            
        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer(1,"Dave","Sarasota"));
        customers.Add(new Customer(2,"John","Tampa"));
        customers.Add(new Customer(3,"Abe","Miami"));

        Customer abe = customers.Find((Customer c) => c.Name.Equals("Abe"));
    }
}

Combining Extension Methods and Lambda Expressions for Help In Finding Our Customer

Let’s say we have a custom CustomerCollection Class not within our control that doesn’t provide us an easy way to find a Customer:

public class CustomerCollection : IEnumerable<Customer>
{
    IEnumerable<Customer> _customers;

    public CustomerCollection(IEnumerable<Customer> customers)
    {
        _customers = customers;
    }

    public IEnumerator<Customer> GetEnumerator()
    {
        foreach (Customer customer in _customers)
            yield return customer;
    }

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

Let’s add an Extension Method to the CustomerCollection Class, called GetCustomer:

public static class CustomerExtensions
{
    public static Customer GetCustomer(this CustomerCollection customers, Predicate<Customer> isMatch)
    {
        foreach (Customer customer in customers)
            if (isMatch(customer))
                return customer;
        return null;
    }
}

And now, we can use the CustomerCollection Class to easily find Abe like:

class Program
{
    static void Main(string[] args)
    {                    
        CustomerCollection collection = GetCustomers();    

        // Using my GetCustomer Method Extension that accepts my Lamda Expression...
        Customer abe = collection.GetCustomer(c => c.Name.Equals("Abe"));
    }
    
    // Pretend We Don't See This :)
    static CustomerCollection GetCustomers()
    {
        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer(1,"Dave","Sarasota"));
        customers.Add(new Customer(2,"John","Tampa"));
        customers.Add(new Customer(3,"Abe","Miami"));
        
        return new CustomerCollection(customers);
    }
}

But This Is LINQ!

But, of course, since CustomerCollection implements IEnumerable<T>, in this case, IEnumerable<Customer>, screw the Extension Methods and just use LINQ:

class Program
{
    static void Main(string[] args)
    {                    
        CustomerCollection collection = GetCustomers();    

        // LINQ
        var abe = collection.Single(c => c.Name.Equals("Abe"));
    }
    
    // Pretend We Don't See This :)
    static CustomerCollection GetCustomers()
    {
        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer(1,"Dave","Sarasota"));
        customers.Add(new Customer(2,"John","Tampa"));
        customers.Add(new Customer(3,"Abe","Miami"));
        
        return new CustomerCollection(customers);
    }
}
Advertisements
 

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s