意外行为寄托在C#中的对象

问题描述:

我与ImageSharp LIB打了C#,当我执行该代码意外行为寄托在C#中的对象

using SixLabors.ImageSharp; 
using SixLabors.ImageSharp.Advanced; 
using System; 
using System.IO; 
using System.Runtime.InteropServices; 
using System.Threading.Tasks; 
namespace ImageSharp 
{ 
    public class Program 
    { 
     public static void Main() 
     { 
      Image<Rgba32> img = null; 
      using (var imageFileStream = new FileStream(/*Any jpg image.*/@"E:\cat\0.jpg", FileMode.Open, FileAccess.Read, FileShare.Read)) 
      { 
       img = Image.Load(imageFileStream); 
      } 
      int length = img.Height * img.Width/2; 
      //Rgba32[] colors = typeof(Rgba32).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(a => a.FieldType == typeof(Rgba32)).Select(a => (Rgba32)a.GetValue(null)).ToArray(); 
      Span<Rgba32> buffer = Span<Rgba32>.Empty; 
      GCHandle bufferHandle = GCHandle.Alloc(img.DangerousGetPinnableReferenceToPixelBuffer(), GCHandleType.Pinned); 
      unsafe 
      { 
       buffer = new Span<Rgba32>(bufferHandle.AddrOfPinnedObject().ToPointer(), length); 
      } 
      for (int i = 0; i < length; i++) 
      { 
       buffer[i] = Rgba32.Yellow; 
       Console.WriteLine(i);//exception thrown here 
      } 
      buffer = Span<Rgba32>.Empty; 
      bufferHandle.Free(); 
      GC.Collect(); 
      using (var imageFileStream = new FileStream(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), @"ImageSharp.jpg"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) 
      { 
       img.SaveAsJpeg(imageFileStream); 
       imageFileStream.Flush(); 
      } 
      Console.WriteLine("Done!"); 
      Console.ReadLine(); 
     } 
    } 
} 

我得到这个异常时(System.IO.IOException:“的句柄无效”) 。 如果你删除了引发异常的那一行,程序就会挂起(我认为它会挂在循环中)。

所以我的问题是什么导致这个异常,为什么当你删除“Console.WriteLine”程序将挂起?

该项目中唯一的依赖项是ImageSharp nuget包。 Framework版本:4.7.1

+0

你的标题说“GCHandle.Free后出现意外的行为”,但是在你调用之前异常发生了吗? – Evk

+0

@Evk对不起,我已经更新了标题。 – abdallahesam

它看起来像你试着对缓冲区,并使用Span<T>

你的错误走路它是在这里。

GCHandle.Alloc(img.DangerousGetPinnableReferenceToPixelBuffer(), GCHandleType.Pinned); 

你拳击表示图像的第一像素结构,并创建一个GCHandle到装箱的对象实例。

如果您确实需要固定缓冲区,我会建议您这样做。

fixed (Rgba32* ptr = &img.DangerousGetPinnableReferenceToPixelBuffer()) 
{ 
    Console.WriteLine(ptr[42]); // no Span<T> needed! 
} 

然而 ...我真的不明白,为什么你正在试图做到这一点。使用Image<TPixel>[x,y]索引器和可用于Fill像素区域的方法,可通过API获得每像素访问权限。我强烈建议你使用可用的方法。