我需要创建一个删除实例的类方法。
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];
}
}
任何类都不能将其值设置为 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 收集汽车实例的区域并 致力于改善该领域。
IDisposable
接口。
请参阅下面的示例实现。
using System;
public class Car : IDisposable
{
public void Dispose()
{
Dispose(true);
// any other unmanaged 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;
}
}
}
现在在您的代码中:
static void Main()
{
using (var car = new Car())
{
// do something with car
} // here dispose will automtically get called.
}
听起来您需要围绕可以无效的实例创建一个包装器:
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
使其失效。
你问的是不可能的。 .Net 中没有任何机制可以将某个对象的所有引用设置为
null
。
我认为您尝试这样做的事实表明存在某种设计问题。您可能应该考虑根本问题并以另一种方式解决它(这里的其他答案提出了一些选择)。
您可以使用字典单例等代理对对象的引用。您可以存储的不是对象,而是其 ID 或哈希值,并通过字典访问它。然后,当您需要删除该对象时,请将其键的值设置为 null。
您无法在 C# 中删除托管对象。这就是为什么称为托管语言。所以你不必为删除而烦恼(就像在 C++ 中一样)。
确实可以将其实例设置为空。但这对您没有多大帮助,因为您无法控制 GC(垃圾收集器)来删除除 Collect 之外的某些对象。这不是您想要的,因为这会删除您一代中的所有收藏。
那么它是如何做到的呢?所以: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 !!!
使用作为
Car
类的静态属性的集合。
每次创建 Car
的新实例时,请将引用存储在此集合中。
要销毁所有
Car
,只需将所有项目设置为null
即可。
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。
您可以使用扩展方法来实现此目的。
public static ObjRemoverExtension {
public static void DeleteObj<T>(this T obj) where T: new()
{
obj = null;
}
}
然后您只需将其导入所需的源文件中并在任何对象上使用。 GC会收集它。像这样:
Car.DeleteObj()
编辑 抱歉没有注意到类/所有引用部分的方法,但无论如何我都会保留它。