Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#.NET阻止对象处理其不应处理的内容';T_C#_.net_Memory Leaks_Garbage Collection_Dispose - Fatal编程技术网

C#.NET阻止对象处理其不应处理的内容';T

C#.NET阻止对象处理其不应处理的内容';T,c#,.net,memory-leaks,garbage-collection,dispose,C#,.net,Memory Leaks,Garbage Collection,Dispose,我在一个大项目中工作,出现了一个问题:假设我有一个加载到内存中的数据库,它存储了广泛使用的数据。但是如果数据没有加载到内存中,我必须进行管理,因此我必须下载数据,然后在完成后进行处理 但我很容易犯错误:我可以像手动加载数据库一样处理它。 我想阻止自己处理数据库,即使我在DB上调用Dispose()方法 我想到了跟踪谁可以处理数据库的想法。当然,唯一允许这样做的人是创建数据库实例的人 记录的问题示例: using System; using System.Collections.Generic;

我在一个大项目中工作,出现了一个问题:假设我有一个加载到内存中的数据库,它存储了广泛使用的数据。但是如果数据没有加载到内存中,我必须进行管理,因此我必须下载数据,然后在完成后进行处理

但我很容易犯错误:我可以像手动加载数据库一样处理它。 我想阻止自己处理数据库,即使我在DB上调用
Dispose()
方法

我想到了跟踪谁可以处理数据库的想法。当然,唯一允许这样做的人是创建数据库实例的人

记录的问题示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DisposePrevention
{
    /// <summary>
    /// A bottle containing alcoholics
    /// </summary>
    class Bottle:IDisposable
    {
        private static int Id = 0;

        private int localId;

        public Bottle()
        {
            this.localId = Bottle.Id++;
        }

        public void Dispose()
        {
            //do the trick.
        }

        public override string ToString()
        {
            return "Bottle - " + this.localId.ToString();
        }
    }

    /// <summary>
    /// A shelf storing bottles
    /// </summary>
    class Shelf : IDisposable
    {
        public List<Bottle> Content;

        public void Fill()
        {
            if (this.Content == null)
            {
                this.Content = new List<Bottle>();
            }

            for (int i = 0; i < 5; i++)
            {
                this.Content.Add(new Bottle());
            }
        }

        public void Dispose()
        {
            if (this.Content == null)
            {
                return;
            }

            foreach (Bottle b in this.Content)
            {
                b.Dispose();
            }
        }
    }

    /// <summary>
    /// A bartender serving drinks
    /// </summary>
    class Bartender : IDisposable // very simplified.
    {
        public List<Shelf> Shelves;

        public Bartender()
        {
            this.Shelves = new List<Shelf>();

            for (int i = 0; i < 3; i++)
            {
                Shelf s = new Shelf();
                s.Fill();
                this.Shelves.Add(s);
            }
        }

        public void Dispose()
        {
            if (this.Shelves != null)
            {
                foreach (Shelf actualShelf in this.Shelves)
                {
                    if ((actualShelf == null) || actualShelf.Content == null)
                    {
                        continue;
                    }

                    foreach (Bottle bottleItem in actualShelf.Content)
                    {
                        bottleItem.Dispose(); // We can call this, because Content is public, but we shouldn't.
                    }

                    actualShelf.Dispose();
                }

                this.Shelves.Clear();
            }
        }

        /// <summary>
        /// What can we drink, Sir?
        /// </summary>
        public void Print()
        {
            Console.WriteLine("------------------");
            if (this.Shelves != null)
            {
                foreach (Shelf actualShelf in this.Shelves)
                {
                    if ((actualShelf == null) || actualShelf.Content == null)
                    {
                        continue;
                    }

                    foreach (Bottle bottleItem in actualShelf.Content)
                    {
                        Console.WriteLine(bottleItem.ToString());
                    }
                }
            }
            Console.WriteLine("------------------");
        }

        /// <summary>
        /// Two bartenders can use the same source of drinks.
        /// </summary>
        /// <param name="list"></param>
        internal void AttachShelves(List<Shelf> list)
        {
            this.Shelves = list;
        }

        /// <summary>
        /// The boss can fire him, so he no longer gets access to the drinks.
        /// </summary>
        internal void DetachShelves()
        {
            this.Shelves = null;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Bartender john = new Bartender();
            Bartender steven = new Bartender();

            steven.AttachShelves(john.Shelves);

            Console.WriteLine("John:");
            john.Print();
            Console.WriteLine("Steven");
            steven.Print();

            Console.WriteLine("");
            Console.WriteLine("Calling Dispose.");
            Console.WriteLine("");

            john.Dispose(); // we kick John. But at this point, we should've called "john.DetachShelves();"
            Console.WriteLine("John");
            john.Print();

            Console.WriteLine("Steven");
            steven.Print(); // Steven is sad. We should not allow John to dispose the alcoholics.

            Console.ReadLine();
        }
    }
}
  • 我不能使用pinted
    GCHandle
    -s来防止泄漏(引用保存到防止
    GC
    收集的对象)
  • 一般来说,我不能指望垃圾收集器。我必须处理我创建的所有东西,GC只收集很少的东西
  • 修改最少的解决方案是最好的
  • 我不能使用
    不安全的
    代码。。。(这是一个WPF和Silverlight项目)
想法:我可以编写一个包装器,但引用问题仍然存在

问题:

我想阻止John调用书架上的Dispose()。是否有这样做的“最佳实践”

提前感谢

编辑:包装器

    /// <summary>
    /// A shelf storing bottles
    /// </summary>
    class ShelfWrapped : IDisposable
    {
        public List<Bottle> Content;

        public void Fill()
        {
            if (this.Content == null)
            {
                this.Content = new List<Bottle>();
            }

            for (int i = 0; i < 5; i++)
            {
                this.Content.Add(new Bottle());
            }
        }

        public void Dispose()
        {
            if (this.Content == null)
            {
                return;
            }

            foreach (Bottle b in this.Content)
            {
                b.Dispose();
            }
        }
    }

    /// <summary>
    /// Wrapper for a shelf storing bottles
    /// </summary>
    class Shelf:IDisposable
    {
        private ShelfWrapped InnerShelf = null;

        public Shelf()
        {
            this.InnerShelf = new ShelfWrapped();
        }

        public void Fill()
        {
            if (this.InnerShelf == null)
            {
                this.InnerShelf = new ShelfWrapped();
            }

            this.InnerShelf.Fill();
        }

        public ShelfWrapped GetShelf()
        {
            return this.InnerShelf;
        }

        private List<Bartender> AllowedToDispose = new List<Bartender>();

        public void Dispose(object disposer)
        {
            if (this.AllowedToDispose.Contains(disposer))
            {
                if (InnerShelf != null)
                {
                    this.InnerShelf.Dispose();
                }
            }
        }

        public void Dispose()
        {
            // And again, John can dispose the shelf...
        }
    }
//
///存放瓶子的架子
/// 
类搁置:IDisposable
{
公开列表内容;
填空
{
if(this.Content==null)
{
this.Content=新列表();
}
对于(int i=0;i<5;i++)
{
this.Content.Add(新瓶子());
}
}
公共空间处置()
{
if(this.Content==null)
{
返回;
}
foreach(本品中的b瓶内容)
{
b、 处置();
}
}
}
/// 
///用于存放瓶子的架子的包装物
/// 
类别:IDisposable
{
私有ShelfWrapped InnerShelf=null;
公共货架()
{
this.InnerShelf=新ShelfRapped();
}
填空
{
if(this.InnerShelf==null)
{
this.InnerShelf=新ShelfRapped();
}
this.InnerShelf.Fill();
}
公共搁置已被搁置的GetShelf()
{
把这个放回书架;
}
私有列表AllowedDispose=新列表();
公共空间处理(对象处理程序)
{
如果(此.AllowedDispose.Contains(处理器))
{
如果(InnerShelf!=null)
{
this.InnerShelf.Dispose();
}
}
}
公共空间处置()
{
//再说一次,约翰可以处理架子。。。
}
}

我认为GC应该由框架来处理。在.NET出现之前,我曾试图对内存进行微观管理,这是必要的,但它只会导致“奇怪”的问题。我的建议是不要麻烦GC甚至.dispose。只有在项目(非托管对象)中实现COM时,才真正需要Dispose。有关更多信息,请参见此-

一般来说,一次性对象应该有明确的所有者,并且对象应该只处理它们拥有的东西。有时,可能需要有一个字段,该字段由某个类型的某些实例拥有,而不是由其他实例拥有;在这些情况下,应该将字段与另一个字段组合起来,以指示它是否拥有所讨论的实例。例如,如果类
FunStream
继承自
Stream
并包装
,则如果创建它的代码不再使用底层流,则实例在被释放时应该调用底层流,但是,如果创建它的代码在
FunStream
被释放后希望继续使用
,则不应释放它。由于创建
FunStream
的代码将知道它期望的模式,因此
FunStream
构造函数或工厂方法应提供一个参数,以指示
FunStream
是否应承担流的所有权


当一个对象实际上是不可变的,但却封装了资源时,才会出现造成重大困难的唯一情况。不可变对象通常是可自由共享的,因此通常是共享的。虽然资源应该在无人需要时释放,但预测哪个不可变对象将是最后一个使用资源的对象通常很困难。处理这种情况的最佳方法可能是使用一个
LifetimeManager
类,该类将使用一些
ConditionalWeakTable
对象与每个类关联一个弱引用列表,该列表指向仍在使用它的对象,并提供一个
DisposeIfNotNeeded(IDisposable资源,对象所有者)
;这将从仍然需要资源的对象列表中删除
owner
,并在不再保留所有者时处置资源。然而,我不知道有任何现有的实现,这样一个东西的设计可能会有点棘手。尽管如此,使用这样一个类可能是确保正确处理封装资源的共享对象的最干净的方法。

数据库的静态实例(Singleton)或者使用每个用户将实例化和处理自己的db实例的使用模式。您能更好地解释在什么情况下不应该处理对象吗?它是否被对象图的其他部分使用?是不是因为它们是某种类型的?@RAJ:这将是最好的解决方案,成本是吨级的te
    /// <summary>
    /// A shelf storing bottles
    /// </summary>
    class ShelfWrapped : IDisposable
    {
        public List<Bottle> Content;

        public void Fill()
        {
            if (this.Content == null)
            {
                this.Content = new List<Bottle>();
            }

            for (int i = 0; i < 5; i++)
            {
                this.Content.Add(new Bottle());
            }
        }

        public void Dispose()
        {
            if (this.Content == null)
            {
                return;
            }

            foreach (Bottle b in this.Content)
            {
                b.Dispose();
            }
        }
    }

    /// <summary>
    /// Wrapper for a shelf storing bottles
    /// </summary>
    class Shelf:IDisposable
    {
        private ShelfWrapped InnerShelf = null;

        public Shelf()
        {
            this.InnerShelf = new ShelfWrapped();
        }

        public void Fill()
        {
            if (this.InnerShelf == null)
            {
                this.InnerShelf = new ShelfWrapped();
            }

            this.InnerShelf.Fill();
        }

        public ShelfWrapped GetShelf()
        {
            return this.InnerShelf;
        }

        private List<Bartender> AllowedToDispose = new List<Bartender>();

        public void Dispose(object disposer)
        {
            if (this.AllowedToDispose.Contains(disposer))
            {
                if (InnerShelf != null)
                {
                    this.InnerShelf.Dispose();
                }
            }
        }

        public void Dispose()
        {
            // And again, John can dispose the shelf...
        }
    }