C# 如何使用C将一个对象的生存期与另一个对象的生存期联系起来#

C# 如何使用C将一个对象的生存期与另一个对象的生存期联系起来#,c#,.net,garbage-collection,C#,.net,Garbage Collection,假设您有一个.net对象bufferObject,它在内部使用某种相当大的非托管内存缓冲区。它的实现方式是在释放(或最终确定)时释放其分配的内存 然后创建一个不同的对象reusingBufferObject,并为其提供指向bufferObject的内部缓冲区的指针。所以这两个物体本身并不知道彼此的存在 如果bufferObject超出范围并被释放/最终确定,内部缓冲区将被释放,reusingBufferObject将访问无效内存 当然,通过改变两个对象的基础类的设计并让重用bufferObjec

假设您有一个.net对象
bufferObject
,它在内部使用某种相当大的非托管内存缓冲区。它的实现方式是在释放(或最终确定)时释放其分配的内存

然后创建一个不同的对象
reusingBufferObject
,并为其提供指向
bufferObject
内部缓冲区的指针。所以这两个物体本身并不知道彼此的存在

如果
bufferObject
超出范围并被释放/最终确定,内部缓冲区将被释放,
reusingBufferObject
将访问无效内存

当然,通过改变两个对象的基础类的设计并让
重用bufferObject
引用
bufferObject
可以避免整个问题。但是让我们假设这两个对象都是第三方类的实例,并且它们的设计不能更改

一个例子是使用一些图像处理库。内部图像对象必须转换为
位图
对象才能在屏幕上显示,但出于性能原因,
位图
对象必须重复使用图像对象内部缓冲区,而不仅仅是复制到它

是否可以将
bufferObject
的生存期与
reusingBufferObject
的生存期绑定,以便只有在
reusingBufferObject
完成后,它才有资格进行垃圾收集,而不必手动跟踪生存期

编辑:

下面是一个简单的例子来说明这个问题:

namespace Example
{
    // Some third party class with no control over its design.
    // The Data property is the pointer to an unmanaged memory
    // buffer.
    public class ThirdPartyImage : IDisposable
    {
        public int Width { get; }
        public int Height { get; }
        public int Stride { get; }
        public PixelFormat Format { get; }
        public IntPtr Data { get; }

        public ThirdPartyImage(string filename);
        public Dispose();
    }

    public static class MyOwnExtensions
    {
        // Some method to reuse the internal memory buffer.
        public static Bitmap ToBitmap(this ThirdPartyImage image)
        {
            return new Bitmap(image.Width, image.Height, image.Stride, image.Format,
                image.Data);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Bitmap bitmap = Foo();

            // ThirdPartyImage is not referenced anymore and the internal buffer (Data)
            // will be freed when garbage collected.

            Bar(bitmap);
        }

        private static Bitmap Foo()
        {
            ThirdPartyImage image = ThirdPartyImage("foo.bmp");
            Bitmap bitmap = image.ToBitmap();

            return bitmap;
        }

        private static void Bar(Bitmap bitmap)
        {
            // Do some Bitmap related work here.
            // The buffer could already be freed though.
        }
    }
}
编辑:

我要寻找的是一种类似于垃圾收集的方法,它可以让你将一个对象的生命周期与另一个对象的生命周期联系起来

或者当正在收集
重用缓冲对象
/
位图
或符合收集条件时发出某种通知,因此,我可以构建一些自动机制,其中包括一个helper对象,该对象包含对
bufferObject
的强引用和对
重用bufferObject
WeakReference


手动跟踪两个实际上不再需要的对象(除了其内部使用的缓冲区),例如通过引入包装类,对我来说似乎过于复杂。

创建对象的人负责处理它们。如果您有
objectA
objectA
需要
objectB
,但这两个对象都是由第三个对象
objectC
创建的,则
objectC
需要确保同时处理这两个对象

这是需要记住的最重要的一点:创建者负责处理


这是一些IoC容器的最大问题之一:它们创建了一些东西,但当涉及到处理时,这些东西会留给其他人,这使得事情变得非常棘手。

创建对象的人负责处理它们。如果您有
objectA
objectA
需要
objectB
,但这两个对象都是由第三个对象
objectC
创建的,则
objectC
需要确保同时处理这两个对象

这是需要记住的最重要的一点:创建者负责处理


这是一些IoC容器的最大问题之一:它们会创建东西,但在处理时,东西会留给其他人,这使得事情变得非常棘手。

您问题的第一部分非常笼统,无法按原样回答。我的回答只尝试回答问题中的特定代码示例

由于
ThirdPartyImage
实现了
IDisposable
,因此它的预期行为是在您对其调用
Dispose()
之前保留该缓冲区。如果不想复制图像缓冲区,则必须在位图的整个生命周期内保留对
ThirdPartyImage
的引用,否则当缓冲区释放且位图无法渲染时,程序将在某个点崩溃

您可以通过多种方式实现这一点-使用由位图设置关键帧的
ThirdPartyImage
实例的全局映射(这很棘手,很快就会成为维护问题),或者您可以将两个对象(
ThirdPartyImage
和位图)保留在一个类中,并传递到每个位置(您可以)。这样,当您准备删除位图时,只需销毁holder对象,该对象将在两个位图上调用
Dispose()
,然后在
ThirdPartyImage
上调用


你可以试着想出一些方法,把这种设置隐藏在某种结构中,这种结构看起来是自动化的,但最终一个对象进入另一个对象,这将它们联系在一起。只有你知道什么时候可以安全地摆脱第一个物体,这样第二个物体也可以离开。

你的问题的第一部分非常笼统,无法按原样回答。我的回答只尝试回答问题中的特定代码示例

由于
ThirdPartyImage
实现了
IDisposable
,因此它的预期行为是在您对其调用
Dispose()
之前保留该缓冲区。如果不想复制图像缓冲区,则必须在位图的整个生命周期内保留对
ThirdPartyImage
的引用,否则当缓冲区释放且位图无法渲染时,程序将在某个点崩溃

您可以通过多种方式实现这一点-使用由位图设置关键帧的
ThirdPartyImage
实例的全局映射(这很棘手,很快就会成为维护问题),或者您可以将两个对象(
ThirdPartyImage
和位图)保留在一个类中,并传递到每个位置(您可以)。这样,当你
public static class MyOwnExtensions
{
    private static readonly ConditionalWeakTable<Bitmap, ThirdPartyImage>
        WeakBitmapImageTable = new ConditionalWeakTable<Bitmap, ThirdPartyImage>();

    public static Bitmap ToBitmap(this ThirdPartyImage image)
    {
        Bitmap bitmap = new Bitmap(image.Width, image.Height, image.Stride, image.Format,
            image.Data);
        WeakBitmapImageTable.Add(bitmap, image);

        return bitmap;
    }
}