泛型
- 泛型无处不在,和谁都有一腿,泛化即模糊抽象化,比如听音乐和听周杰伦的歌,听青花瓷,这就是泛化->特化
- 泛型的重要,除了它无处不再外,常用的数据结构都是泛型的。
- 缺点,泛型T实际上在类中只能当作object使用
为什么需要泛型
类型膨胀
一个商品对应一个盒子,盒子类型膨胀了
成员膨胀
一个盒子装了苹果后,就不装了,其实这盒子还能装书的,这样就浪费了
其他方法
如果使用一个接口或者粗俗点用object声明变量,那么使用这对象的时候,需要判断其类型,然后进行类型转换
泛型登场拯救世界
public Box<类型参数>{},类型参数是一个标识符,代表一个泛化类型,就像上面的音乐,而传入的值是音乐中的一个特化,《青花瓷》。
注意!注意!注意! C# 泛型类必须特化只会才能够使用,这点与JAVA不同,JAVA是特化不是必须的。不特化相当于传入了一个object。特化了就清楚其方法属性了,是强类型的。
class Box<T>
{
public T SomeThing { get; set; }
}
泛型接口
使用方法一
使用方法二
和一的主要区别就是让Student的ID类型定死了ulong
其他:
根据C#必须泛型类特化这特性,那么很多接口都要有泛型版和不泛型版哈哈哈,例如下面的哈哈
泛型方法
方法的成员膨胀更加麻烦,因为这意味着一个方法的逻辑错了,就需要改全部膨胀出来的方法
这里的会自动特化
泛型委托
由于T类型是不能直接使用+号的,所以这里随便乱来了。可以发现,Add方法中T自动赋予了int类型,如果T的操作正常点的化,string也可以作为T的。
class Program
{
static void Main(string[] args)
{
Func<int, int, string> func = Add;
Console.WriteLine(func(1,2));
}
static string Add<T>(T a, T b)
{
Console.WriteLine(a);
Console.WriteLine(b);
return a.ToString() + b.ToString();
}
}
由于T类型不能直接使用运算符+,使用这里只能成员膨胀一下,或者写复杂点的代码
或者采用Lambda表达式,泛型搭配Lambda神器啊!!!!!!
static void Main(string[] args)
{
Func<int, int, int> func =(a,b)=>
{
return a + b;
};
Console.WriteLine(func(1,2));
}
partial分部类型
可以解决数据库中生成代码重置问题。
通过分部类型可以定义要拆分到多个文件中的类、结构、接口或记录。
在 File1.cs 中:
namespace PC
{
partial class A
{
int num = 0;
void MethodA() { }
partial void MethodC();
}
}
在 File2.cs 中,声明:
namespace PC
{
partial class A
{
void MethodB() { }
partial void MethodC() { }
}
}
Lambda 表达式
不同情况三种写法
- 无参数直接()=>{}
- 单个参数x=>{}
- 多个(a,b)=>{}
三种表达
action委托,func委托以及**表达式树**类型
任何 Lambda 表达式都可以转换为委托类型。 Lambda 表达式可以转换的委托类型由其参数和返回值的类型定义。 如果 lambda 表达式不返回值,则可以将其转换为 Action
委托类型之一;否则,可将其转换为 Func
委托类型之一。 例如,有 2 个参数且不返回值的 Lambda 表达式可转换为 Action 委托。 有 1 个参数且不返回值的 Lambda 表达式可转换为 Func 委托。 以下示例中,lambda 表达式 x => x * x
(指定名为 x
的参数并返回 x
平方值)将分配给委托类型的变量:
Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
// Output:
// 25
表达式 lambda 还可以转换为**表达式树**类型,如下面的示例所示:
System.Linq.Expressions.Expression<Func<int, int>> e = x => x * x;
Console.WriteLine(e);
// Output:
// x => (x * x)
可在需要委托类型或表达式树的实例的任何代码中使用 lambda 表达式,例如,作为 Task.Run(Action) 方法的参数传递应在后台执行的代码。
关于LINQ
用 C# 编写 LINQ 时,还可以使用 lambda 表达式,如下例所示:
int[] numbers = { 2, 3, 4, 5 };
var squaredNumbers = numbers.Select(x => x * x);
Console.WriteLine(string.Join(" ", squaredNumbers));
// Output:
// 4 9 16 25
如果使用基于方法的语法在 System.Linq.Enumerable 类中(例如,在 LINQ to Objects 和 LINQ to XML 中)调用 Enumerable.Select 方法,则参数为委托类型 System.Func。
如果在 System.Linq.Queryable 类中(例如,在 LINQ to SQL 中)调用 Queryable.Select 方法,则参数类型为表达式树类型 Expression>
。 在这两种情况下,都可以使用相同的 lambda 表达式来指定参数值。 尽管通过 Lambda 创建的对象实际具有不同的类型,但其使得 2 个 Select
调用看起来类似。
异步 lambda
通过使用 async 和 await 关键字,你可以轻松创建包含异步处理的 lambda 表达式和语句。 例如,下面的 Windows 窗体示例包含一个调用和等待异步方法 ExampleMethodAsync
的事件处理程序。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
}
private async void button1_Click(object sender, EventArgs e)
{
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
}
private async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}
你可以使用异步 lambda 添加同一事件处理程序。 若要添加此处理程序,请在 lambda 参数列表前添加 async
修饰符,如下面的示例所示:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
private async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}
特殊情况
表达式 lambda 的主体可以包含方法调用。 不过,若要创建在 .NET 公共语言运行时 (CLR) 的上下文之外(如在 SQL Server 中)计算的表达式树,则不得在 lambda 表达式中使用方法调用。 在 .NET 公共语言运行时 (CLR) 上下文之外,方法将没有任何意义。