六:C#语言特性

自动实现的属性

C#的属性

    public class Product
    {
        private string name;
        private string address;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public string Address
        {
            get { return address; }
            set { address = value; }
        }
    }

自动实现的属性

    public class Product
    {
        public string Name { get; set; }
        public string Address { get; set; }
    }

这段代码的效果和上面的代码是一样的

对象和集合的初始化器

            Product product = new Product(); 
            product.Name = "MVC";
            product.Address = "MVC";

            Product product2 = new Product()
            {
                Name = "MVC",
                Address = "MVC"
            };

product 和product2的结果一样,但是product2初始化值的方法就称为初始化器,可读性更好。

拓展方法

对应不是自己拥有的类,或者不能直接修改的类,如果要添加方法,就需要使用拓展方法。

    public static class MyExtensionClass
    {
        public static string MyExtensionMethod(this object o)
        {
            return "This is my Extension Method" + o.ToString();
        }
    }

需要说明的几点

  • 定义拓展方法的类修饰符必须是static
  • 修饰拓展方法的修饰符也必须是static
  • 参数的修饰符必须有this,参数类型是要拓展的类

定义了上述拓展方法后,在任何引用定义了该拓展类的命名空间的代码中,所有的对象都会多一个方法MyExtensionMethod。

接口拓展方法

定义了购物类实现了IEnumerable接口

    public class ShoppingCart:IEnumerable<Product>
    {
        public List<Product> products { get; set; }
        public IEnumerator<Product> GetEnumerator()
        {
            return products.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}

对接口IEnumerable<Product>进行拓展

    public static class MyExtensionClass
    {
        public static decimal ProductListExtension(this IEnumerable<Product> products)
        {
            decimal total = 0;
            foreach(Product p in products)
            {
                total += p.Price;
            }
            return total;
        }
    }

那么在使用ShoppingCart类时,就可以直接使用该拓展方法

        public string Test()
        {
            ShoppingCart cart = new ShoppingCart();
            return cart.ProductListExtension().ToString();
        }

过滤拓展方法

对集合进行过滤,是对IEnumerable<T>进行操作

新建一个和拓展方法2,这个拓展方法和上面的差别在于这个方法多了一个string类型的参数,用来过滤Name

        public static decimal ProductListExtension2(this IEnumerable<Product> products,string NameFilter)
        {
            decimal total = 0;
            foreach (Product p in products)
            {
                if (p.Name.Contains(NameFilter))
                {
                    total += p.Price;
                }
            }
            return total;
        }

使用该拓展方法

        public string Test()
        {
            ShoppingCart cart = new ShoppingCart();
            return cart.ProductListExtension2("C#").ToString();
        }

Lambda表达式

拓展方法的好处不言而喻,但是缺点是不够灵活,比如如果我新增了其他属性,过滤的不是Name而是新增属性。

那么上面的拓展方法就不能用了。

现在新建拓展方法3

        public static decimal ProductListExtension3(this IEnumerable<Product> products, Func<Product,bool> selectParam)
        {
            decimal total = 0;
            foreach (Product p in products)
            {
                if (selectParam(p))
                {
                    total += p.Price;
                }
            }
            return total;
        }

使用该拓展方法

        public string Test()
        {
            ShoppingCart cart = new ShoppingCart();
            Func<Product,bool> NameFilter=delegate(Product p)
            {
                return p.Name.Contains("C#");
            };
            Func<Product, bool> PriceFilter = delegate(Product p)
            {
                return p.Price > 100;
            };
            return cart.ProductListExtension3(PriceFilter).ToString();
        }

可以看到这个拓展方法的通用性变的更好了。我们可以自定义过滤的条件,而拓展方法的接受是通用的。

但是还有一个问题在于定义Func还是太复杂。

        public string Test4()
        {
            ShoppingCart cart = new ShoppingCart();
            Func<Product,bool> NameFilter=delegate(Product p)
            {
                return p.Name.Contains("C#");
            };
            Func<Product, bool> PriceFilter = delegate(Product p)
            {
                return p.Price > 100;
            };
            Func<Product, bool> PriceFilter2 = p => p.Price > 100;
            return cart.ProductListExtension3(PriceFilter2).ToString();
        }

这里定义的PriceFilter2就是抛弃掉代理,而使用一种更简洁的语句,这就是Lambda表达式。

总结:Lambda就是委托更简洁的表达。

自动类型

C#允许定义一个局部变量而不指定变量类型。这称为类型推断,或隐式类型。

var MyProduct = new Product { Name="C#"};

匿名类型

C#允许创建一个数据存储对象,而不需要定义类或结构

            var MyAnonProduct = new { MyName="C#",MyPrice=123};
            decimal d = MyAnonProduct.MyPrice;

可以看到可以直接引用MyAnonProduct对象的内容。而实际上并没有定义一个类。

LINQ(执行语言集合查询)

        public string Test()
        {
            Product[] products = { 
                                     new Product{Name="Test",Address="111",Price=111},
                                     new Product{Name="C#",Address="222",Price=222},
                                     new Product{Name=".NET",Address="333",Price=333},
                                     new Product{Name="MVC",Address="444",Price=444}
                                 };
            var foundProducts = from p in products
                                orderby p.Price descending
                                where p.Name.Contains("C")
                                select new { p.Name, p.Price };
            return foundProducts.Count().ToString();
        }

运行得到结果是2。其中计算变量foundProducts的表达式就是LINQ。这中表达式类似SQL。

还有一种另外一种拓展方法来使用LINQ。

            var foundProducts2 = products.Where(item => item.Name.Contains("C"))
                .OrderByDescending(item=>item.Price);    

效果和上面的一样。

延迟的LINQ查询。

        public string Test()
        {
            Product[] products = { 
                                     new Product{Name="Test",Address="111",Price=111},
                                     new Product{Name="C#",Address="222",Price=222},
                                     new Product{Name=".NET",Address="333",Price=333},
                                     new Product{Name="MVC",Address="444",Price=444}
                                 };
            var foundProducts2 = products.Where(item => item.Name.Contains("C"))
                .OrderByDescending(item=>item.Price);
            products[0].Name = "C++";
            return foundProducts2.Count().ToString();
        }

在执行了LINQ查询之后,按照正常理解这时候foundProducts2的数量应该是2。但是下面这条语句重新给第一个Product的Name赋值了C++。执行了这个方法的结果不是2而是3。也就证明了其实LINQ语句只是定义了查询语句,而没有执行查询。真正执行查询的是在最后一句。这就称为延迟查询。

但是并不是所有的LINQ语句都是延迟的。

posted @ 2018-10-31 11:16  岚山夜话  阅读(171)  评论(0编辑  收藏  举报