C# 如果在异步方法中使用,为什么GetManifestResourceStream返回null?
在我的程序中,我将资源文件写入用户选择的某个位置。为此,我使用GetManifestResourceStream。一切都很顺利 接下来,我想让我的写操作不阻塞UI。因此,我使用async await更改了代码。 不幸的是,GetManifestRresourceStream现在返回null。在不使用异步的情况下切换回,等待一切再次正常工作 我做错了什么?我如何解决它,以便能够复制文件,并且UI不会被阻止 这就是在没有async/await的情况下它是如何工作的(请不要被方法名称弄糊涂) 这就是我用async/await尝试的方法C# 如果在异步方法中使用,为什么GetManifestResourceStream返回null?,c#,wpf,async-await,.net-assembly,C#,Wpf,Async Await,.net Assembly,在我的程序中,我将资源文件写入用户选择的某个位置。为此,我使用GetManifestResourceStream。一切都很顺利 接下来,我想让我的写操作不阻塞UI。因此,我使用async await更改了代码。 不幸的是,GetManifestRresourceStream现在返回null。在不使用异步的情况下切换回,等待一切再次正常工作 我做错了什么?我如何解决它,以便能够复制文件,并且UI不会被阻止 这就是在没有async/await的情况下它是如何工作的(请不要被方法名称弄糊涂) 这就是我
private async Task CopyFileToDestinationAsync(string nameSpace,string outDirectory, string internalPath, string resourceName)
{
Assembly assembly = Assembly.GetCallingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(nameSpace + "." + (internalPath == "" ? "" : internalPath + ".") + resourceName))
{
using( BinaryReader br = new BinaryReader(stream))
{
using(FileStream fs = new FileStream(outDirectory + "\\" + resourceName, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
await Task.Run( ()=> bw.Write(br.ReadBytes((int)stream.Length)));
// bw.Write(br.ReadBytes((int)stream.Length));
}
}
}
}
//Thread.Sleep(2000);
//For User Friendliness wait 2 seconds to finish
await Task.Run(() => Thread.Sleep(2000));
}
private void FinishButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.Application.Current.Shutdown();
}
private async void InstallProgrammAsyc()
{
try
{
FinalMessage = "";
PreInstallationBlock.Visibility = Visibility.Collapsed;
DuringInstallationBlock.Visibility = Visibility.Visible;
await CopyFileToDestinationAsync("MyNameSpace", InstallPath, "Resources", "some.exe");
PrepareProgrammForFinish();
}
catch (Exception ex)
{
DuringInstallationBlock.Visibility = Visibility.Collapsed;
AfterInstallationBlock.Visibility = Visibility.Visible;
FinalMessage = $"Unexpected Error occured. Please try again. {ex.Message}";
}
}
private void InstallButton_Click(object sender, RoutedEventArgs e)
{
InstallProgrammAsyc();
}
这是一个有趣的边缘情况,因为异步是如何工作的 让我们看看这些测试方法:
private void Button_Click(object sender, RoutedEventArgs e)
{
ShowAssembly();
ShowAssemblyAsync();
}
private void ShowAssembly()
{
Assembly assembly = Assembly.GetCallingAssembly();
MessageBox.Show(assembly.FullName);
}
private async void ShowAssemblyAsync()
{
Assembly assembly = Assembly.GetCallingAssembly();
MessageBox.Show(assembly.FullName);
}
在ShowAssembly
中,它将显示程序主程序集的名称。在ShowAssemblyAsync中,它将显示“mscorlib”。发生什么事了
如果在Visual Studio中的ShowAssembly
和ShowAssemblyAsync
中放置断点,您将获得以下调用堆栈:
DesktopClient.exe!DesktopClient.MainWindow.ShowAssembly() Line 119 C#
DesktopClient.exe!DesktopClient.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 109 C#
00efe58c 07cf423b DesktopClient.MainWindow.ShowAssembly()
00efe5a8 07cf41dc DesktopClient.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs)
那里没什么可疑的。然而,VisualStudio正在欺骗您。如果改用较低级别的调试器(在本例中为WinDbg),则会得到以下调用堆栈:
DesktopClient.exe!DesktopClient.MainWindow.ShowAssembly() Line 119 C#
DesktopClient.exe!DesktopClient.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 109 C#
00efe58c 07cf423b DesktopClient.MainWindow.ShowAssembly()
00efe5a8 07cf41dc DesktopClient.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs)
您可以看到,在应用async关键字后,ShowAssemblyAsync
中的调用堆栈已完全更改(Visual Studio正在隐藏该关键字以使调试更容易)。一个结果是,System.Runtime.CompilerServices.asynchvoidMethodBuilder.Start
现在调用该方法,这就是为什么在检索调用程序集时会得到“mscorlib”
作为修复,您可以使用Assembly.getExecutionGassembly
(假设您的CopyFileToDestinationAsync
方法位于右侧程序集中)或显式地将程序集作为目标:typeof(MainWindow).Assembly
。或者,就像您所做的那样,在调用方法之前检索流
另一种方法是引入额外的非异步方法,以便在调用真正的异步实现之前检索程序集:
private Task CopyFileToDestinationAsync(string nameSpace,string outDirectory, string internalPath, string resourceName)
{
Assembly assembly = Assembly.GetCallingAssembly();
return CopyFileToDestinationAsync(assembly, nameSpace, outDirectory, internalPath, resourceName);
}
private async Task CopyFileToDestinationAsync(Assembly assembly string nameSpace,string outDirectory, string internalPath, string resourceName)
{
using (Stream stream = assembly.GetManifestResourceStream(nameSpace + "." + (internalPath == "" ? "" : internalPath + ".") + resourceName))
{
// ...
}
}
这是一个有趣的边缘情况,因为异步是如何工作的 让我们看看这些测试方法:
private void Button_Click(object sender, RoutedEventArgs e)
{
ShowAssembly();
ShowAssemblyAsync();
}
private void ShowAssembly()
{
Assembly assembly = Assembly.GetCallingAssembly();
MessageBox.Show(assembly.FullName);
}
private async void ShowAssemblyAsync()
{
Assembly assembly = Assembly.GetCallingAssembly();
MessageBox.Show(assembly.FullName);
}
在ShowAssembly
中,它将显示程序主程序集的名称。在ShowAssemblyAsync中,它将显示“mscorlib”。发生什么事了
如果在Visual Studio中的ShowAssembly
和ShowAssemblyAsync
中放置断点,您将获得以下调用堆栈:
DesktopClient.exe!DesktopClient.MainWindow.ShowAssembly() Line 119 C#
DesktopClient.exe!DesktopClient.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 109 C#
00efe58c 07cf423b DesktopClient.MainWindow.ShowAssembly()
00efe5a8 07cf41dc DesktopClient.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs)
那里没什么可疑的。然而,VisualStudio正在欺骗您。如果改用较低级别的调试器(在本例中为WinDbg),则会得到以下调用堆栈:
DesktopClient.exe!DesktopClient.MainWindow.ShowAssembly() Line 119 C#
DesktopClient.exe!DesktopClient.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 109 C#
00efe58c 07cf423b DesktopClient.MainWindow.ShowAssembly()
00efe5a8 07cf41dc DesktopClient.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs)
您可以看到,在应用async关键字后,ShowAssemblyAsync
中的调用堆栈已完全更改(Visual Studio正在隐藏该关键字以使调试更容易)。一个结果是,System.Runtime.CompilerServices.asynchvoidMethodBuilder.Start
现在调用该方法,这就是为什么在检索调用程序集时会得到“mscorlib”
作为修复,您可以使用Assembly.getExecutionGassembly
(假设您的CopyFileToDestinationAsync
方法位于右侧程序集中)或显式地将程序集作为目标:typeof(MainWindow).Assembly
。或者,就像您所做的那样,在调用方法之前检索流
另一种方法是引入额外的非异步方法,以便在调用真正的异步实现之前检索程序集:
private Task CopyFileToDestinationAsync(string nameSpace,string outDirectory, string internalPath, string resourceName)
{
Assembly assembly = Assembly.GetCallingAssembly();
return CopyFileToDestinationAsync(assembly, nameSpace, outDirectory, internalPath, resourceName);
}
private async Task CopyFileToDestinationAsync(Assembly assembly string nameSpace,string outDirectory, string internalPath, string resourceName)
{
using (Stream stream = assembly.GetManifestResourceStream(nameSpace + "." + (internalPath == "" ? "" : internalPath + ".") + resourceName))
{
// ...
}
}
我通过在外部调用GetManifestResourceStream函数并将流作为参数传递给异步函数来解决这个问题。但是,我很想知道为什么它没有像我以前尝试的那样工作。很可能
Assembly.GetCallingAssembly
没有返回您期望的程序集是的。我也试着用其他的。但这也没有帮助,我通过在外部调用GetManifestResourceStream函数并将流作为参数传递给异步函数来解决问题。但是,我很想知道为什么它没有像我以前尝试的那样工作。很可能Assembly.GetCallingAssembly
没有返回您期望的程序集是的。我也试着用其他的。但那也没用。非常感谢。这真的有助于更好地理解。非常感谢。这确实有助于更好地理解。