WPF上位机开发之第五课->委托
一.认识委托->不打不相识
菜鸟入行的时候,犯了一个错误,跨线程更新UI界面。
遇到问题怎么办呢?当然是上网一顿搜索,搜索完找到了解决方案:
报错原因:
-
在Windows Forms中,UI控件只能在创建它们的线程(主线程/UI线程)中访问和修改
-
当我们在Task.Run中执行代码时,代码是在后台线程中运行的
-
直接修改UI控件(如label1.Text)会导致跨线程访问异常
Task.Run(() =>
{
try
{
for (int i = 0; i < 10; i++)
{
// Simulate some work
System.Threading.Thread.Sleep(1000);
//label1.Text = $"Task running... {i + 1}/10";
//方法一: Update the UI By Winform
this.Invoke((MethodInvoker)delegate
{
label1.Text = $"Task running... {i + 1}/10";
});
// 方法二:Update the UI using Invoke
this.Invoke(new Action(() => { label1.Text = $"Task running... {i + 1}/10"; }));
}
}
catch (Exception ex)
{
// Handle exceptions
MessageBox.Show($"An error occurred: {ex.Message}");
}
} );
-
第一种使用MethodInvoker委托,这是Windows Forms专门提供的一个无参数无返回值的委托类型
-
第二种使用Action委托,这是.NET Framework提供的通用委托类型
-
两种方式都能达到相同的目的,但MethodInvoker是专门为Windows Forms设计的,语义上更明确
二.面试中的委托
后来参加面试的时候,总是会遇到这样的对话:谈谈你对委托的认识。
太理论的我也讲不上来,主要是一下几点吧
1.委托是class,我反编译后查到委托就是class,所以我们在定义委托的时候,需要跟class平级。
2.委托相当于C/C++里的函数指针
3.说说我平时用到委托的地方
A.跨线程修改界面控件的值
B.回调函数->常用于取相机拍照产生的图像数据
不使用Action,Func的版本
public class DataProcessor
{
// 定义回调委托
public delegate void ProcessingCallback(string result);
public void ProcessData(string data, ProcessingCallback callback)
{
// 模拟耗时操作
Thread.Sleep(1000);
// 调用回调
callback($"Processed: {data}");
}
}
class Program
{
static void Main()
{
var processor = new DataProcessor();
// 使用回调
processor.ProcessData("Hello", result =>
{
Console.WriteLine(result);
});
}
}
C.把函数单座参数进行传递
- 看Task
[__DynamicallyInvokable]
public static Task Run(Action action)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default, TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
}
- 看Thread
[SecuritySafeCritical]
public Thread(ThreadStart start)
{
if (start == null)
{
throw new ArgumentNullException("start");
}
SetStartHelper(start, 0);
}
- 再看ThreadStart
[ComVisible(true)]
public delegate void ThreadStart();
D…NET内置了Action和Func两个委托,一个是不带返回值的,一个是带返回值的,他们最多可以有16个参数。
特性 | Action | Func |
---|---|---|
定义 | 无返回值的委托 | 有返回值的委托 |
返回值 | 无 | 有 |
参数 | 可有0个或多个输入参数 | 可有0个或多个输入参数,但必须有返回值 |
用途 | 执行操作,如事件处理、回调 | 执行计算或查询,返回结果 |
是否可以作为Lambda表达式 | 是 | 是 |
是否可以作为匿名方法 | 是 | 是 |
是否可以作为方法组 | 是 | 是 |
是否可以作为事件处理器 | 是 | 不适合(事件处理器通常无返回值) |
是否可以作为方法参数 | 是 | 是 |
是否可以作为方法返回值 | 不适合(无返回值) | 是 |
是否可以作为异步方法的返回值 | 不适合 | 可以(返回Task<T> ) |
E.Linq查询:用于数据查询和转换
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 使用委托进行过滤
var evenNumbers = numbers.Where(n => n % 2 == 0);
// 使用委托进行转换
var squares = numbers.Select(n => n * n);
// 使用委托进行排序
var sorted = numbers.OrderBy(n => n);
Console.WriteLine("Even numbers: " + string.Join(", ", evenNumbers));
Console.WriteLine("Squares: " + string.Join(", ", squares));
Console.WriteLine("Sorted: " + string.Join(", ", sorted));
}
}
三.Net中的其他委托
主要的内置委托类型总结:
1.Action系列
-
Action:无参数无返回值
-
Action:一个参数无返回值
-
Action<T1, T2>:两个参数无返回值
-
最多支持16个参数
2.Func系列
-
Func:无参数有返回值
-
Func<T, TResult>:一个参数有返回值
-
Func<T1, T2, TResult>:两个参数有返回值
-
最多支持16个参数
3.Predicate
-
接受一个参数,返回bool
-
常用于条件判断
-
例如:List.FindAll(Predicate)
4.Comparison
-
接受两个参数,返回int
-
用于比较两个对象
-
例如:List.Sort(Comparison)
5.Converter<TInput, TOutput>
-
接受一个输入类型,返回输出类型
-
用于类型转换
-
例如:List.ConvertAll(Converter<T, TOutput>)
6/EventHandler
-
用于处理无参数事件
-
签名:void (object sender, EventArgs e)
7.EventHandler
-
用于处理带参数的事件
-
签名:void (object sender, TEventArgs e)
这些内置委托类型覆盖了大多数常见的委托使用场景。选择使用哪种委托主要取决于:
-
是否需要返回值
-
参数的个数
-
参数的类型
-
具体的应用场景
在实际开发中,这些内置委托类型可以大大简化代码,避免重复定义相似的委托类型。
四Action的一些示例
1.基本示例
class Program
{
static void Main()
{
// 无参数Action
Action sayHello = () => Console.WriteLine("Hello!");
sayHello(); // 输出: Hello!
// 一个参数Action
Action<string> greet = name => Console.WriteLine($"Hello, {name}!");
greet("Alice"); // 输出: Hello, Alice!
// 两个参数Action
Action<string, int> printInfo = (name, age) =>
Console.WriteLine($"{name} is {age} years old.");
printInfo("Bob", 30); // 输出: Bob is 30 years old.
// 三个参数Action
Action<string, int, string> printDetails = (name, age, city) =>
Console.WriteLine($"{name}, {age} years old, lives in {city}");
printDetails("Charlie", 25, "New York"); // 输出: Charlie, 25 years old, lives in New York
}
}
2.1回调函数Lambda版本
class DataProcessor
{
// 使用Action作为回调,不需要返回值
public void ProcessData(string data, Action<string> callback)
{
Console.WriteLine("Processing data...");
Thread.Sleep(1000); // 模拟耗时操作
// 处理完成后调用回调
string result = $"Processed: {data}";
callback(result);
}
}
class Program
{
static void Main()
{
var processor = new DataProcessor();
// 示例1:简单的回调
processor.ProcessData("Hello", result =>
{
Console.WriteLine($"Callback received: {result}");
});
// 示例2:更新UI的回调
processor.ProcessData("UI Update", result =>
{
// 假设这是在Windows Forms应用中
// this.Invoke(() => label1.Text = result);
Console.WriteLine($"UI Updated: {result}");
});
// 示例3:多步骤处理
processor.ProcessData("Multi-step", result =>
{
Console.WriteLine($"Step 1: {result}");
processor.ProcessData(result, secondResult =>
{
Console.WriteLine($"Step 2: {secondResult}");
});
});
}
}
2.2回调函数不用Lambda版本
class DataProcessor
{
// 使用Action作为回调,不需要返回值
public void ProcessData(string data, Action<string> callback)
{
Console.WriteLine("Processing data...");
Thread.Sleep(1000); // 模拟耗时操作
// 处理完成后调用回调
string result = $"Processed: {data}";
callback(result);
}
}
class Program
{
// 定义回调方法
static void SimpleCallback(string result)
{
Console.WriteLine($"Callback received: {result}");
}
// 定义UI更新回调方法
static void UpdateUICallback(string result)
{
// 假设这是在Windows Forms应用中
// this.Invoke(() => label1.Text = result);
Console.WriteLine($"UI Updated: {result}");
}
// 定义多步骤处理的回调方法
static void MultiStepCallback(string result, DataProcessor processor)
{
Console.WriteLine($"Step 1: {result}");
processor.ProcessData(result, SecondStepCallback);
}
// 定义第二步的回调方法
static void SecondStepCallback(string result)
{
Console.WriteLine($"Step 2: {result}");
}
static void Main()
{
var processor = new DataProcessor();
// 示例1:简单的回调
processor.ProcessData("Hello", SimpleCallback);
// 示例2:更新UI的回调
processor.ProcessData("UI Update", UpdateUICallback);
// 示例3:多步骤处理
processor.ProcessData("Multi-step", result => MultiStepCallback(result, processor));
}
}
3.实现观察者模式
// 主题(被观察者)
class Subject
{
private string state;
private List<Action<string>> observers = new List<Action<string>>();
public string State
{
get => state;
set
{
state = value;
NotifyObservers();
}
}
// 注册观察者
public void Attach(Action<string> observer)
{
observers.Add(observer);
}
// 移除观察者
public void Detach(Action<string> observer)
{
observers.Remove(observer);
}
// 通知所有观察者
private void NotifyObservers()
{
foreach (var observer in observers)
{
observer(state);
}
}
}
// 观察者
class Observer
{
private string name;
public Observer(string name)
{
this.name = name;
}
// 观察者的更新方法
public void Update(string state)
{
Console.WriteLine($"{name} received update: {state}");
}
}
class Program
{
static void Main()
{
// 创建主题
var subject = new Subject();
// 创建观察者
var observer1 = new Observer("Observer 1");
var observer2 = new Observer("Observer 2");
// 注册观察者
subject.Attach(observer1.Update);
subject.Attach(observer2.Update);
// 改变主题状态,观察者会收到通知
subject.State = "State 1";
subject.State = "State 2";
// 移除一个观察者
subject.Detach(observer1.Update);
// 再次改变状态,只有observer2会收到通知
subject.State = "State 3";
}
}
五Func的一些示例
1.基础示例
class Program
{
static void Main()
{
// Func<T, TResult> - 接受一个参数,返回一个结果
Func<int, int> square = x => x * x;
Console.WriteLine($"Square of 5: {square(5)}"); // 输出: 25
// Func<T1, T2, TResult> - 接受两个参数,返回一个结果
Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine($"Sum of 5 and 3: {add(5, 3)}"); // 输出: 8
// Func<T1, T2, T3, TResult> - 接受三个参数,返回一个结果
Func<int, int, int, int> multiply = (x, y, z) => x * y * z;
Console.WriteLine($"Product of 2, 3, 4: {multiply(2, 3, 4)}"); // 输出: 24
}
}
2.回调函数
class Calculator
{
// 使用Func作为回调,需要返回值
public int Calculate(int a, int b, Func<int, int, int> operation)
{
Console.WriteLine($"Calculating with {a} and {b}");
return operation(a, b);
}
// 使用Func作为回调,返回处理后的数据
public T ProcessData<T>(T data, Func<T, T> transform)
{
Console.WriteLine("Processing data...");
Thread.Sleep(1000); // 模拟耗时操作
return transform(data);
}
}
class Program
{
static void Main()
{
var calculator = new Calculator();
// 示例1:基本计算回调
int sum = calculator.Calculate(5, 3, (x, y) => x + y);
Console.WriteLine($"Sum: {sum}");
int product = calculator.Calculate(5, 3, (x, y) => x * y);
Console.WriteLine($"Product: {product}");
// 示例2:数据处理回调
string result = calculator.ProcessData("hello", str => str.ToUpper());
Console.WriteLine($"Uppercase: {result}");
// 示例3:复杂数据处理
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var processed = calculator.ProcessData(numbers, list =>
{
return list.Select(x => x * 2)
.Where(x => x > 5)
.ToList();
});
Console.WriteLine($"Processed numbers: {string.Join(", ", processed)}");
}
}
3.在linq中的使用
class Program
{
static void Main()
{
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 35 }
};
// 使用Func进行筛选
Func<Person, bool> isAdult = p => p.Age >= 18;
var adults = people.Where(isAdult);
// 使用Func进行转换
Func<Person, string> getName = p => p.Name;
var names = people.Select(getName);
// 使用Func进行排序
Func<Person, int> getAge = p => p.Age;
var sortedByAge = people.OrderBy(getAge);
Console.WriteLine("Adults:");
foreach (var person in adults)
{
Console.WriteLine($"{person.Name} - {person.Age}");
}
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
4.实现观察者模式
// 主题(被观察者)
class Subject
{
private string state;
private List<Func<string, bool>> observers = new List<Func<string, bool>>();
public string State
{
get => state;
set
{
state = value;
NotifyObservers();
}
}
// 注册观察者
public void Attach(Func<string, bool> observer)
{
observers.Add(observer);
}
// 移除观察者
public void Detach(Func<string, bool> observer)
{
observers.Remove(observer);
}
// 通知所有观察者
private void NotifyObservers()
{
foreach (var observer in observers)
{
bool success = observer(state);
if (!success)
{
Console.WriteLine("Observer failed to process update");
}
}
}
}
// 观察者
class Observer
{
private string name;
private int maxUpdates;
private int updateCount;
public Observer(string name, int maxUpdates)
{
this.name = name;
this.maxUpdates = maxUpdates;
this.updateCount = 0;
}
// 观察者的更新方法,返回是否成功处理
public bool Update(string state)
{
if (updateCount >= maxUpdates)
{
Console.WriteLine($"{name} has reached maximum updates");
return false;
}
updateCount++;
Console.WriteLine($"{name} received update {updateCount}: {state}");
return true;
}
}
class Program
{
static void Main()
{
// 创建主题
var subject = new Subject();
// 创建观察者
var observer1 = new Observer("Observer 1", 2); // 最多处理2次更新
var observer2 = new Observer("Observer 2", 3); // 最多处理3次更新
// 注册观察者
subject.Attach(observer1.Update);
subject.Attach(observer2.Update);
// 改变主题状态,观察者会收到通知
subject.State = "State 1";
subject.State = "State 2";
subject.State = "State 3"; // observer1将不再处理
subject.State = "State 4"; // observer1和observer2都不再处理
}
}
完结,撒花!!!