14

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

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];
     }
}
4

9 回答 9

22

在任何类中,您都不能将其值设置为 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 收集汽车实例的区域并努力改进该区域。

于 2013-10-20T11:22:28.927 回答
12

如果您想在使用后释放实例,我建议您使用 .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. 
}
于 2013-10-20T11:25:03.863 回答
5

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

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.

于 2013-10-20T11:33:30.057 回答
2

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

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

于 2013-10-20T11:43:32.387 回答
1

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

于 2013-10-20T11:28:47.707 回答
1

您不能在 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 !!!
于 2013-10-20T11:35:50.393 回答
0

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

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

于 2015-07-16T00:21:37.943 回答
0

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。

于 2020-10-24T18:38:17.467 回答
-1

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

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

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

编辑 抱歉没有注意到类/所有引用部分的方法,但无论如何我都会留下它。

于 2013-10-20T11:46:18.433 回答