Maison >développement back-end >Tutoriel C#.Net >[ASP.NET MVC Mavericks Road] 02 - Résumé des points de connaissances C#
[ASP.NET
MVC Mavericks Road] 02 - Résumé des points de connaissances C#
Ce billet de blog fournit principalement un bref aperçu des points de connaissances du langage C# qui doivent être maîtrisés dans asp.net développement mvc. Surtout certaines fonctionnalités du langage C# qui ne sont disponibles qu'en C# 3.0. Pour ceux qui apprennent asp.net mvc, autant passer quelques minutes à le parcourir. Les points de connaissances C# qui seront examinés dans cet article incluent : les propriétés, les propriétés automatiques, les initialiseurs de collection d'objets, les méthodes d'extension, les expressions Lambda et les requêtes Linq. Les "joueurs" seniors C# peuvent passer.
Contenu de cet article
1. Attributs
Attributs, la définition de MSDN est : le Common Language Runtime vous permet d'ajouter des instructions de description similaires à des mots-clés, appelés attributs, il annote. éléments du programme, tels que les types, les champs, les méthodes, les propriétés, etc. Les attributs sont stockés avec les métadonnées des fichiers Microsoft .NET Framework et peuvent être utilisés pour décrire votre code au moment de l'exécution ou affecter le comportement de l'application lorsque le programme est en cours d'exécution.
Par exemple, si vous marquez l'attribut [Obsolète] avant une méthode, VS affichera un avertissement indiquant que la méthode a expiré lors de l'appel de la méthode, comme indiqué ci-dessous :
Autre exemple, dans l'objet distant de .Net Remoting, si vous souhaitez appeler ou transférer un objet, comme une classe ou une structure, la classe ou la structure doit être marquée avec l'attribut [Serialisisable]. De plus, une fonctionnalité que nous utilisons beaucoup lors de la création de services Web XML est [WebMegthod], qui permet à la valeur de retour de la méthode publique de la requête HTTP d'être codée en XML pour être livrée.
Une caractéristique est en fait une classe. Le nom de classe réel de la caractéristique [Obsolète] est ObsoleteAttribute, mais nous n'avons pas besoin d'ajouter le suffixe d'attribut lors de son annotation, le système nous l'ajoutera automatiquement lors de l'annotation. conversion de nom.
Les fonctionnalités mentionnées ci-dessus sont quelques-unes des fonctionnalités définies par le système .NET, bien sûr, il y en a bien d'autres. Comprendre comment personnaliser les fonctionnalités nous aidera à mieux utiliser les fonctionnalités de la programmation ASP.NET MVC, telles que l'annotation des attributs de la classe Model pour vérifier la légalité des entrées de formulaire (décrit plus loin).
Simulons une fonctionnalité StringLenth souvent utilisée par ASP.NET MVC, qui est utilisée pour déterminer si la saisie de l'utilisateur dépasse la limite de longueur. Simulons-le maintenant. Définissez d'abord un attribut MyStringLenth :
// 用户自定义的带有可选命名参数的 MyStringLenthAttribute 特性类。 // 该特性通过AttributeUsage限制它只能用在属性和字段上。 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public sealed class MyStringLenthAttribute : Attribute { public MyStringLenthAttribute(string displayName, int maxLength) { this.MaxLength = maxLength; this.DisplayName = displayName; } //显示的名称,对外是只读的,所以不能通过可选参数来赋值,必须在构造函数中对其初始化。 public string DisplayName { get; private set; } //长度最大值,对外是只读的,所以不能通过可选参数来赋值,必须在构造函数中对其初始化。 public int MaxLength { get; private set; } //错误信息,标注时可作为可选命名参数来使用。 public string ErrorMessage { get; set; } //长度最小值,标注时可作为可选命名参数来使用。 public int MinLength { get; set; } }
Si la restriction AttributeUsage n'est pas ajoutée ci-dessus, l'attribut peut être déclaré en types (tels que les structures, les classes, les énumérations, les délégués) et en membres (tels que les méthodes, les champs). , événements, propriétés, index).
Ensuite, nous appliquons cette fonctionnalité à la classe Order suivante :
// 应用自定义MyStringLenth特性于Order类的OrderID属性之上。MinLength和ErrorMessage是命名参数。 public class Order { [MyStringLenth("订单号", 6,MinLength = 3, ErrorMessage = "{0}的长度必须在{1}和{2}之间,请重新输入!")] public string OrderID { get; set; } }
Enfin, nous voyons comment utiliser la fonctionnalité MyStringLenth pour vérifier la longueur de la chaîne de saisie utilisateur :
//检查成员字符串长度是否越限。 private static bool IsMemberValid(int inputLength, MemberInfo member) { foreach (object attribute in member.GetCustomAttributes(true)) { if (attribute is MyStringLenthAttribute) { MyStringLenthAttribute attr=(MyStringLenthAttribute)attribute; string displayName = attr.DisplayName; int maxLength = attr.MaxLength; int minLength = attr.MinLength; string msg = attr.ErrorMessage; if (inputLength < minLength || inputLength > maxLength) { Console.WriteLine(msg, displayName, minLength, maxLength); return false; } else { return true; } } } return false; } //验证输入是否合法 private static bool IsValid(Order order) { if (order == null) return false; foreach (PropertyInfo p in typeof(Order).GetProperties()) { if (IsMemberValid(order.OrderID.Length, p)) return true; } return false; } public static void Main() { string input=string.Empty; Order order; do { Console.WriteLine("请输入订单号:"); input = Console.ReadLine(); order = new Order { OrderID = input }; } while (!IsValid(order)); Console.WriteLine("订单号输入正确,按任意键退出!"); Console.ReadKey(); }
L'effet de sortie est le suivant :
2 Attributs automatiques
En C# 3.0 et versions ultérieures, lorsque l'accesseur de l'attribut n'est pas. requis Lors de l'utilisation d'une autre logique, les propriétés implémentées automatiquement peuvent rendre les déclarations de propriétés plus concises.
L'exemple suivant illustre l'implémentation standard et l'implémentation automatique des propriétés :
class Program { class Person { //标准实现的属性 int _age; public int Age { get { return _age; } set { if (value < 0 || value > 130) { Console.WriteLine("设置的年龄有误!"); return; } _age = value; } } //自动实现的属性 public string Name { get; set; } } static void Main(string[] args) { Person p = new Person(); p.Age = 180; p.Name = "小王"; Console.WriteLine("{0}今年{1}岁。",p.Name,p.Age); Console.ReadKey(); } }
Les propriétés automatiques peuvent également avoir différents droits d'accès, tels que :
public string Name { get;private set; }
Notez que les propriétés automatiques ne peuvent pas définir de propriétés en lecture seule ou en écriture seule, et doivent fournir à la fois des accesseurs get et set :
public string Name { get; }//编译出错 public string PetName { set; }//编译出错
3. Initialiseurs pour objets et collections
上面我们演示自动属性的时候给对象的实例初始化时是一个一个属性进行赋值的,有多少个属性就需要多少句代码。C# 3.0和更高版本中有了对象集合初始化器,有了它,只需一句代码就可初始化一个对象或一个对象集合的所有属性。这在里先创建一个“商品”类,用于后面的示例演示:
/// <summary> /// 商品类 /// </summary> public class Product { /// <summary> /// 商品编号 /// </summary> public int ProductID { get; set; } /// <summary> /// 商品名称 /// </summary> public string Name { get; set; } /// <summary> /// 商品描述 /// </summary> public string Description { get; set; } /// <summary> /// 商品价格 /// </summary> public decimal Price { get; set; } /// <summary> /// 商品分类 /// </summary> public string Category { set; get; } }
基于上面定义好的商品类,下面代码演示了如何通过初始化器来创建商品类的实例对象和集合:
static void Main(string[] args) { //对象初始化器的使用 (可只给部分字段赋值) Product product = new Product { ProductID = 1234, Name = "西瓜", Price = 2.3M };//创建并初始化一个实例 //集合初始化器的使用 List<Product> proList = new List<Product> { new Product { ProductID = 1234, Name = "西瓜", Price = 2.3M }, new Product { ProductID = 2345, Name = "苹果", Price = 5.9M }, new Product { ProductID = 3456, Name = "樱桃", Price = 4.6M } }; //打印 Console.WriteLine("对象初始化器:{0} {1} {2}", product.ProductID, product.Name, product.Price); foreach (Product p in proList) { Console.WriteLine("集合初始化器:{0} {1} {2}", p.ProductID, p.Name, p.Price); } Console.ReadKey(); }
另外还有一些其它类型也可以使用初始化器,如下:
/数组使用初始化器 string[] fruitArray = {"apple","orange","plum" }; //匿名类型使用初始化器 var books = new { Title = "ASP.NET MVC 入门", Author = "小王", Price = 20 }; //字典类型使用初始化器 Dictionary<string, int> fruitDic = new Dictionary<string, int>() { { "apple", 10 }, { "orange", 20 }, { "plum", 30 } };
4.扩展方法
扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型或修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。例如,我们可以让Random类的所有实例对象拥有一个返回随机bool值的方法。我们不能对Random类本身进行修改,但可以对它进行扩展,如下代码所示:
static class Program { /// <summary> /// 随机返回 true 或 false /// </summary> /// <param name="random">this参数自动指定到Random的实例</param> /// <returns></returns> public static bool NextBool(this Random random) { return random.NextDouble() > 0.5; } static void Main(string[] args) { //调用扩展方法 Random rd = new Random(); bool bl = rd.NextBool(); Console.WriteLine(bl.ToString()); Console.ReadKey(); } }
注意,扩展方法必须在非泛型的静态类中定义,上面的Program类如不加static修饰符则会报错。
我们可以创建一个接口的扩展方法,这样实现该接口的类都可以调用该扩展方法。看下面一个完整示例:
/// <summary> /// 购物车类 (实现 IEnumerable<Product> 接口) /// </summary> public class ShoppingCart : IEnumerable<Product> { public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator() { return Products.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } /// <summary> /// 定义一个静态类,用于实现扩展方法(注意:扩展方法必须定义在静态类中) /// </summary> public static class MyExtensionMethods { /// <summary> /// 计算商品总价钱 /// </summary> public static decimal TotalPrices(this IEnumerable<Product> productEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } } class Program { static void Main(string[] args) { // 创建并初始化ShoppingCart实例,注入IEnumerable<Product> IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { new Product {Name = "Kayak", Price = 275}, new Product {Name = "Lifejacket", Price = 48.95M}, new Product {Name = "Soccer ball", Price = 19.50M}, new Product {Name = "Corner flag", Price = 34.95M} } }; // 创建并初始化一个普通的Product数组 Product[] productArray = { new Product {Name = "Kayak", Price = 275M}, new Product {Name = "Lifejacket", Price = 48.95M}, new Product {Name = "Soccer ball", Price = 19.50M}, new Product {Name = "Corner flag", Price = 34.95M} }; // 取得商品总价钱:用接口的方式调用TotalPrices扩展方法。 decimal cartTotal = products.TotalPrices(); // 取得商品总价钱:用普通数组的方式调用TotalPrices扩展方法。 decimal arrayTotal = productArray.TotalPrices(); Console.WriteLine("Cart Total: {0:c}", cartTotal); Console.WriteLine("Array Total: {0:c}", arrayTotal); Console.ReadKey(); } }
执行后输出如下结果:
5.Lambda 表达式
Lambda 表达式和匿名函数其实是一件事情。不同是,他们语法表现形式不同,Lambda 表达式在语法上实际上就是匿名函数的简写。直接介绍匿名函数和Lambda表达式的用法没什么意思,在这里,我要根据实际应用来讲一个两者用法的例子,这样在介绍知识点的同时也能和大家分享一下解决问题的思想。
假如我们要实现一个功能强大的商品查询方法,这个商品查询方法如何查询商品是可以由用户自己来决定的,用户可以根据价格来查询商品,也可以根据分类来查询商品等等,也就是说用户可以把自己的查询逻辑传递给这个查询方法。要编写这样一个方法,我们很自然的会想到用一个委托来作为这个方法的参数,这个委托就是用户处理商品查询的逻辑。 我们不防把这个查询方法称为“商品查询器”。我们可以用静态的扩展方法来实现这个“商品查询器“,这样每个商品集合对象(如 IEnumerable
/// <summary> /// 定义一个静态类,用于实现扩展方法 /// </summary> public static class MyExtensionMethods { /// <summary> /// 商品查询器 /// </summary> /// <param name="productEnum">扩展类型的实例引用</param> /// <param name="selectorParam">一个参数类型为Product,返回值为bool的委托</param> /// <returns>查询结果</returns> public static IEnumerable<Product> Filter(this IEnumerable<Product> productEnum, Func<Product, bool> selectorParam) { foreach (Product prod in productEnum) { if (selectorParam(prod)) { yield return prod; } } } }
没错,我们就是用这么简短的Filter方法来满足各种需求的查询。上面Product类使用的是前文定义的。这里也再一次见证了扩展方法的功效。为了演示Filter查询方法的调用,我们先来造一批数据:
static void Main(string[] args) { // 创建商品集合 IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { new Product {Name = "西瓜", Category = "水果", Price = 2.3M}, new Product {Name = "苹果", Category = "水果", Price = 4.9M}, new Product {Name = "ASP.NET MCV 入门", Category = "书籍", Price = 19.5M}, new Product {Name = "ASP.NET MCV 提高", Category = "书籍", Price = 34.9M} } }; }
接下来我们继续在上面Main方法中来调用查询方法Filter:
//用匿名函数定义一个具体的查询需求 Func<Product, bool> fruitFilter = delegate(Product prod) { return prod.Category == "水果"; }; //调用Filter,查询分类为“水果”的商品 IEnumerable<Product> filteredProducts = products.Filter(fruitFilter); //打印结果 foreach (Product prod in filteredProducts) { Console.WriteLine("商品名称: {0}, 单价: {1:c}", prod.Name, prod.Price); } Console.ReadKey();
输出结果为:
上面我们使用的是委托和匿名函数来处理用户查询逻辑,并把它传递给Filter方法,满足了前面所说的需求。但若使用Lambda表达式代替上面的匿名函数能使上面的代码看上去更简洁更人性化,如下代码所示:
Func<Product, bool> fruitFilter = prod => prod.Category == "水果"; IEnumerable<Product> filteredProducts = products.Filter(fruitFilter);
没有了delegate关键字,没有了大小括号,看上去更舒服。当然上面两行代码可以继续简化为一行:
IEnumerable<Product> filteredProducts = products.Filter(prod => prod.Category == "水果");
这三种方式输出结果都是一样的。然后,我们还可以通过Lambda表达式实现各种需求的查询:
//查询分类为“水果”或者单价大于30元的商品 IEnumerable<Product> filteredProducts = products.Filter(prod => prod.Category == "水果" || prod.Price > 30 );
通过这个示例,相信大家已经清晰的了解并撑握了Lambda表达式的简单应用,而这就足够了:)。
6.LINQ
最后简单回顾一下LINQ。LINQ(Language Integrated Query语言集成查询)是 VS 2008 和 .NET Framework 3.5 版中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。
上面讲Lambda表达式时,用到的查询结果集的方式未免还是有点麻烦(因为自定义了一个Filter扩展方法),而Linq本身就集合了很多扩展方法,我们可以直接使用,大大的简化了编写查询代码的工作。例如,对于这样一个数据集合:
Product[] products = { new Product {Name = "西瓜", Category = "水果", Price = 2.3M}, new Product {Name = "苹果", Category = "水果", Price = 4.9M}, new Product {Name = "空心菜", Category = "蔬菜", Price = 2.2M}, new Product {Name = "地瓜", Category = "蔬菜", Price = 1.9M} };
如果要查询得到价钱最高的三个商品信息,如果不使用Linq,我们可能会先写一个排序方法,对products根据价钱由高到低进行排序,排序时需要创建一个新的Product[]对象用于存储排序好的数据。但用Linq可大大减少工作量,一两句代码就能搞定。如下代码所示,查出价钱最高的三个商品:
var results = from product in products orderby product.Price descending select new { product.Name, product.Price }; //打印价钱最高的三个商品 int count = 0; foreach (var p in results) { Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price); if (++count == 3) break; } Console.ReadKey();
输出结果:
能熟练使用Linq是一件很爽的事情。上面的Linq语句和我们熟悉的SQL查询语句类似,看上去非常整洁且易懂。但并不是每一种SQL查询语句在C#都有对应的关键字,有时候我们需要使用另外一种Linq查询方式,即“点号”方式的Linq查询方式,这种方式中的Linq查询方法都是扩展方法。如下面这段代码和上面实现的效果是一样的:
var results = products .OrderByDescending(e => e.Price) .Take(3) .Select(e => new { e.Name,e.Price}); foreach (var p in results) { Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price); } Console.ReadKey();
虽然类SQL的Linq查询方式比这种方式看上去更一目了然,但并不是每一种SQL查询语句在C#都有对应的关键字,比如这里的Take扩展方法就是类SQL的Linq查询语法没有的功能。
注意,有些Linq扩展方法分为“延后查询”(deferred)和“即时查询”(immediate)。延后查询意思是拥有“延后查询”扩展方法的Linq语句只有当调用结果集对象的时候才开始真正执行查询,即时查询则是立即得到结果。比如上面的Linq语句的OrderByDescending扩展方法就是一个“延后查询”方法,当程序执行到Linq语句定义部分时并没有查询出结果并放到results对象中,而是当程序执行到foreach循环时才真正执行Linq查询语句得到查询结果。我们可以做个测试,在Ling语句之后,我们再将products[1]对象重新赋值,如下代码所示:
var results = products .OrderByDescending(e => e.Price) .Take(3) .Select(e => new { e.Name, e.Price }); //在Linq语句之后对products[1]重新赋值 products[1] = new Product { Name = "榴莲", Category = "水果", Price = 22.6M }; //打印 foreach (var p in results) { Console.WriteLine("商品:{0},价钱:{1}", p.Name, p.Price); } Console.ReadKey();
输出结果为:
我们发现results是重新赋值之后的结果。可想而知,查询语句是在results被调用之后才真正执行的。
Linq非常强大也非常好用,这里只是把它当作一个学习ASP.NET MVC之前需掌握的知识点进行简单回顾。要灵活熟练地使用Linq还需要经常使用才行。
以上就是[ASP.NET MVC 小牛之路]02 - C#知识点提要的内容,更多相关内容请关注PHP中文网(www.php.cn)!