【问题标题】:How to delete object?如何删除对象?
【发布时间】:2013-10-28 21:28:51
【问题描述】:

我需要创建一个删除实例的类方法。

public class Car
{
    private string m_Color;

    public string Color
    {
        get { return m_Color; }
        set { m_Color = value; }
    }

    public Car()
    {
    }

    public void Delete()
    {
        /*This method will delete the instance,
        so any references to this instance will be now null*/
    }
}

class Program
{
    static void Main( string[] args )
    {
        Car car = new Car();

        car.Delete();

        if(car==null)
            Console.WriteLine("It works.");
        else
            Console.WriteLine("It doesn't work.")
    }
}

我想知道是否有任何可能的解决方案(即使不推荐)如何做到这一点。

这个类的实例将存储在数百个不同的类中。我将尝试描述这一点,例如会有这些类:

public class CarKey
{
    private Car m_Car;

    public Car Car
    {
        get { return m_Car; }
    }

    public bool CarExist{ get{ return m_Car != null; } }

    public CarKey( Car car )
    {
        m_Car = car;
    }
}

public class Garages
{
     private List<Car> m_Collection = new List<Car>();

     private int m_Size;

     public int Size{ get{ return m_Size; } }

     public Garages( int size )
     {
         for(int i=0;i<size;i++)
             m_Collection.Add(null);
     }

     public bool IsEmpty( int garage )
     {
         return m_Collection[garage] == null;
     }

     public void InsertCar( Car car, int garage )
     {
          if( m_Collection[garage] != null )
            throw new Exception("This garage is full.");

          m_Collection[garage] = car;
     }


     public Car GetCar( int garage )
     {
         if( m_Collection[garage] == null )
           throw new Exception("There is no car, maybe it was deleted.");

         return m_Collection[garage];
     }
}

【问题讨论】:

  • 为什么不用car.Delete() 而不是简单的car = null
  • /*此方法将删除实例,因此对该实例的任何引用现在都将为空*/ 因此有关空分配的任何答案都是不正确的。
  • 为什么需要这样做?当没有更多对它们的引用时,.NET 中的垃圾收集器将从内存中删除您的对象。您实际上要完成垃圾收集器不为您做的事情?听起来您面临的实际问题在设计中的其他地方。打个比方,您是在询问如何执行第 5 步,但您在第 2 步走错了方向。
  • 如果你需要强制垃圾收集器那么你可以 GC.Collet()
  • 亲爱的 StackOverflow:与其想出更多创造性的方法来删除实例,不如尝试帮助 OP 解决他的实际问题?在Old Shoe and a Glass Bottle 之间做出决定时,他不需要帮助。

标签: c# memory-management


【解决方案1】:

在任何类中,您都不能将其值设置为 null。这是不允许的,也没有意义 -

public void Delete()
{
    this = null; <-- NOT ALLOWED
}

你需要一个类的实例来调用Delete() 方法,所以一旦你完成它,为什么不将该实例设置为null。

Car car = new Car();
// Use car objects and once done set back to null
car = null;

无论如何,您想要实现的目标在 C# 中是不可能的。我猜测 从你的问题中你想要这个,因为有内存泄漏 存在于您当前的设计中,它不允许 Car 实例 离开。我建议您更好地描述您的应用程序和 识别正在停止 GC 以收集汽车实例的区域和 努力改进该领域。

【讨论】:

  • 使用此命令,您将汽车引用设置为 null,如果有其他对同一对象的引用,它们仍将指向同一对象。
  • @jannagy02 - 这就是我在回答中提到的,这样做是不可行的。
  • this = null; 是不允许的,但如果对象是任何事物的子对象(很可能是),则可以使用 Parent.Controls.Remove(this)
【解决方案2】:

如果您想在使用后释放实例,我建议您使用 .Net 的 IDisposable 接口。

请参阅下面的示例实现。

public class Car : IDisposable
{

   public void Dispose()
   {  
      Dispose(true);
       // any other managed resource cleanups you can do here
       Gc.SuppressFinalize(this);
   }
   ~Car()      // finalizer
   {
        Dispose(false);
   }

   protected virtual void Dispose(bool disposing)
   {
     if (!_disposed)
     {
      if (disposing)
      {
        if (_stream != null) _stream.Dispose(); // say you have to dispose a stream
      }

      _stream = null;
    _disposed = true;
    }

   }
}

现在在您的代码中:

void main()
{
   using(var car = new Car())
   {
     // do something with car
   } // here dispose will automtically get called. 
}

【讨论】:

  • 为什么在这种情况下调用 SupressFinalize?没有什么要完成的……即使 OP 已经定义了终结器。
  • @SimonWhitehead 感谢您的指出。我的错,我有点懒得解释这些东西。现在更新了整个实现..
【解决方案3】:

听起来您需要围绕一个可以使您无效的实例创建一个包装器:

public class Ref<T> where T : class
{
    private T instance;
    public Ref(T instance)
    {
        this.instance = instance;
    }

    public static implicit operator Ref<T>(T inner)
    {
        return new Ref<T>(inner);
    }

    public void Delete()
    {
        this.instance = null;
    }

    public T Instance
    {
        get { return this.instance; }
    }
}

你可以像这样使用它:

Ref<Car> carRef = new Car();
carRef.Delete();
var car = carRef.Instance;     //car is null

但是请注意,如果任何代码将内部值保存在变量中,则不会通过调用 Delete 来使其无效。

【讨论】:

    【解决方案4】:

    你问的是不可能的。 .Net 中没有任何机制可以将对某个对象的所有引用设置为 null

    而且我认为您尝试这样做的事实表明存在某种设计问题。您可能应该考虑潜在的问题并以另一种方式解决它(此处的其他答案提出了一些选择)。

    【讨论】:

      【解决方案5】:

      您可以使用例如字典单例来代理对对象的引用。您可以存储的不是对象,而是它的 ID 或散列,并通过字典访问它。然后,当您需要删除对象时,您将其键的值设置为 null。

      【讨论】:

        【解决方案6】:

        您不能在 C# 中删除托管对象。这就是为什么被称为管理语言。所以你不必用 delete 来困扰自己(就像在 c++ 中一样)。

        确实可以将它的实例设置为空。但这对您没有太大帮助,因为您无法控制 GC(垃圾收集器)来删除收集之外的一些对象。这不是您想要的,因为这会从一代人中删除您所有的收藏。

        那么它是如何完成的呢?所以:GC 会定期搜索不再使用的对象,并使用与您无关的内部机制删除该对象。

        When you set an instance to null you just notify that your object has no referene anymore ant that could help CG to collect it faster !!!
        

        【讨论】:

        • GC.Collect 收集所有世代......不仅仅是“一代”。
        • @Simon Whitehead 对不起。确实是的!
        • @user1576055 这就是为什么被称为安全语言的原因。我认为我的回答是正确的。如果你想辩论它是这样的:在 c++ 中,我们经常会遇到一些情况,其中一个对象的实例被删除或移动,这种情况可能会导致内存泄漏。这就是为什么托管语言被告知是安全的。您可以立即停用安全指令并在 c# 语言中使用不安全的块。这将在一定程度上破坏托管语言的目的。如果可以更好地满足您的需求,请尝试使用 unsafe 。
        • 你知道如何删除不安全代码的实例吗?根据 MSDN 文档,只有结构和一些基本类型(例如 int、long、double 等)可以通过指针访问。但我需要访问我的 Car 类的实例并将其删除。
        【解决方案7】:

        使用作为Car 类的静态属性的集合。 每次创建 Car 的新实例时,将引用存储在此集合中。

        要销毁所有Cars,只需将所有项目设置为null

        【讨论】:

        • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
        • @Jonesopolis 我想这就是你为什么不同意的答案?
        • @Knelis 我是新来的,不知道你能把话放在我嘴里,我很沮丧!另外我认为它必须是参考的参考。因为您不想让您的集合为空,而是让所有用户创建的实例为空。
        • 如果其他任何东西也引用了该集合中的项目,那么该对象将不会被垃圾回收。
        【解决方案8】:

        FLCL的思路很正确,我用代码给你看:

            public class O1<T> where T: class
            {
                public Guid Id { get; }
                public O1(Guid id)
                {
                    Id = id;
                }
                public bool IsNull => !GlobalHolder.Holder.ContainsKey(Id);
                public T Val => GlobalHolder.Holder.ContainsKey(Id) ? (T)GlobalHolder.Holder[Id] : null;
            }
            public class GlobalHolder
            {
                public static readonly Dictionary<Guid, object> Holder = new Dictionary<Guid, object>();
                public static O1<T> Instantiate<T>() where T: class, new()
                {
                    var a = new T();
                    var nguid = Guid.NewGuid();
                    var b = new O1<T>(nguid);
                    Holder[nguid] = a;
                    return b;
                }
                public static void Destroy<T>(O1<T> obj) where T: class
                {
                    Holder.Remove(obj.Id);
                }
            }
        
            public class Animal
            {
        
            }
        
            public class AnimalTest
            {
                public static void Test()
                {
                    var tom = GlobalHolder.Instantiate<Animal>();
                    var duplicateTomReference = tom;
                    GlobalHolder.Destroy(tom);
                    Console.WriteLine($"{duplicateTomReference.IsNull}");
                    // prints true
                }
            }
        

        注意:在此代码示例中,我的命名约定来自 Unity。

        【讨论】:

          【解决方案9】:

          您可以使用扩展方法来实现这一点。

          public static ObjRemoverExtension {
              public static void DeleteObj<T>(this T obj) where T: new()
              {
                  obj = null;
              }
          }
          

          然后您只需将其导入所需的源文件并用于任何对象。 GC 将收集它。像这样:Car.DeleteObj()

          编辑 抱歉没有注意到类/所有引用部分的方法,但我还是会留下它。

          【讨论】:

          • OP 不是在寻找一种奇特的方式来调用myCar = null,而是在寻找一种强制使系统中所有持有的实例失效的方法。
          • 再一次,“删除”不是正确的术语。您正在设置对null.. 的引用,而不是删除对象。它仍然在内存中,直到垃圾收集器决定将其删除。那是它被删除的时候。
          猜你喜欢
          • 2019-11-25
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-12
          • 2013-03-21
          • 2023-03-16
          相关资源
          最近更新 更多