【问题标题】:Deconstructor, Dispose don't know what to useDeconstructor, Dispose 不知道用什么
【发布时间】:2012-04-11 17:39:04
【问题描述】:

我在我的程序中遇到了一个小问题。我有一个带有 Socket 的类和一些声明的变量。

现在当我离开定义类的页面时,

Class someclass = new class;

我希望类被“销毁”,这样我就可以在另一个页面上打开一个具有相同端口/IP 的新套接字。 (现在端口和 ip 地址似乎被我不解构/处置/g.c 的类锁定)

因为我有c++背景,这是我第一次使用c#。我不知道从哪里开始,因为在 c++ 中你只需调用析构函数。这将清理您的班级并删除所有活动的套接字/变量。但是我如何在 c# 中实现这一点。我已经阅读了一些关于 Idisposable 类的东西,但这并没有让事情变得更清楚。还有垃圾收集器和正常的解构器。不知道用什么,更重要的是怎么用。


编辑 1

正如下面在 cmets 中所说:这个项目是一个 windows phone 项目,它使用一个外部库来创建一个套接字并设置 windows phone 和 Beckhoff PLC 之间的通信。

我在原始库之上创建了一个额外的层,以使我的变量更易于声明。额外的层看起来像这样:

public class TwincatVar<T> : IDisposable where T : IConvertible
{

    public AdsClient _AdsClient;
    private string _PlcVar;
    private uint _VarHandle;
    private T _Data;
    private DateTime _TimeStamp;
    private bool disposed = false;
    public EventHandler DataChanged;

    //constructor
    public TwincatVar(ref AdsClient AdsClient, string PlcVar)
    {
        //Hook up to the reference of AdsClient
        _AdsClient = AdsClient;

        _PlcVar = PlcVar;

    }

    public async Task InitFunction()
    {

            _VarHandle = await _AdsClient.GetSymhandleByNameAsync(_PlcVar);

            Debug.WriteLine(_VarHandle.ToString());

            _Data = await _AdsClient.ReadAsync<T>(_VarHandle);

            _AdsClient.AddNotificationAsync<T>(_VarHandle, AdsTransmissionMode.OnChange, 1000, this);

    }


    public T Data
    {

        get { return _Data; }
        set
        {
            _Data = value;
            _AdsClient.WriteAsync<T>(_VarHandle, value);
        }
    }

    public DateTime TimeStamp { get { return _TimeStamp; } }

    public void OnDataChangeEvent(T newData)
    {
        _TimeStamp = DateTime.Now;
        _Data = newData;

        //Raise the event
        if (DataChanged != null)
        {
            DataChanged(this, new EventArgs());
        }
    }

}

/* 注意到:IDisposable 那是因为我已经尝试实现它,但效果不佳。 */

public class TwincatDevice : IDisposable
{
    public AdsClient AdsClient;

    //Twincatdevice constructor
    public TwincatDevice(string amsNetIdSource, string ipTarget, string amsNetIdTarget, ushort amsPortTarget = 801)
    {
        AdsClient = new AdsClient(amsNetIdSource, ipTarget, amsNetIdTarget, amsPortTarget);
        AdsClient.OnNotification += DistributeEvent;
    }

    public static void DistributeEvent(object sender, AdsNotificationArgs e)
    {
        AdsNotification notification = e.Notification;


        switch (Type.GetTypeCode((notification.TypeOfValue)))
        {
            case TypeCode.Boolean: ((TwincatVar<bool>)notification.UserData).OnDataChangeEvent((bool)(notification.Value)); break;
            case TypeCode.Byte: ((TwincatVar<byte>)notification.UserData).OnDataChangeEvent((byte)(notification.Value)); break;
            case TypeCode.Int16: ((TwincatVar<short>)notification.UserData).OnDataChangeEvent((short)(notification.Value)); break;
            case TypeCode.Int32: ((TwincatVar<int>)notification.UserData).OnDataChangeEvent((int)(notification.Value)); break;
            case TypeCode.Single: ((TwincatVar<float>)notification.UserData).OnDataChangeEvent((float)(notification.Value)); break;
            case TypeCode.Double: ((TwincatVar<double>)notification.UserData).OnDataChangeEvent((double)(notification.Value)); break;
            case TypeCode.UInt16: ((TwincatVar<ushort>)notification.UserData).OnDataChangeEvent((ushort)(notification.Value)); break;
            case TypeCode.UInt32: ((TwincatVar<uint>)notification.UserData).OnDataChangeEvent((uint)(notification.Value)); break;
            case TypeCode.String: ((TwincatVar<string>)notification.UserData).OnDataChangeEvent((string)(notification.Value)); break;
        }
    }
}

在下面的代码中,我声明了我连接到数据更改事件的“双猫变量”。此外,它们连接到 plc 上的“.name”变量。

 public class MainPageViewModel : ViewModelBase
{
    public TwincatDevice client;       
    public Device _device0;
    public Device _device1;
    public Device _device2;  
    public Devices DeviceList = new Devices();
    public TwincatVar<string> Version;

    //View Model
    public MainPageViewModel()
    {
        //Create devices with initual values
        _device0 = new Device("Device Name", "Status", "Version");
        _device1 = new Device("Device Name", "Status", "Version");
        _device2 = new Device("Device Name", "Status", "Version");

        //Add devices to observablecollection
        DeviceList.Add(_device0);
        DeviceList.Add(_device1);
        DeviceList.Add(_device2);

        // create the connection with the beckhoff device
        _Create_TwincatDevice();
        _Create_Twincatvars();
    }

    ~MainPageViewModel()
    {
    }

    public void _Create_TwincatDevice()
    {
        // This is where the socket is openend !!

//Create TwincatDevice
        client = new TwincatDevice(amsNetIdSource: "192.168.11.216.1.1",
                                   ipTarget: "192.168.11.126",
                                   amsNetIdTarget: "192.168.11.126.1.1");        

    }

    public async Task _Create_Twincatvars()
    {
        // Create Twincat Variable
        Version = new TwincatVar<string>(ref client.AdsClient, ".Version");
        // Init Twincat Variable

        await Version.InitFunction();
        Version.DataChanged += (o, e) =>
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => { _device0.Version = Version.Data; });
        };



        // TwincatVar<type> Name = new TwincatVar<type>(reference to TwincatDevice, "Variable name PLC");

    }

}

}

最后但并非最不重要。在“页面背后的代码”(mainpage.xaml.cs)中,我创建了一个 MainViewModel 实例并将其设置为 datacontext 以进行绑定。

private MainPageViewModel _MV;
_MV = new MainPageViewModel();
Device_listbox.DataContext = _MV.DeviceList;

我希望这会有所帮助,所以你们可以帮助我:)

【问题讨论】:

  • 能否请您展示更多有关如何创建套接字的源代码。您是否使用任何指针来创建套接字并连接到它?您可以在您的班级上使用 Dispose 模式来处理套接字。在 Dispose 方法中,您可以放置​​清理代码。然后在使用类中对该类使用 Using() 块。
  • @zenwalker 这有点问题,因为套接字是在外部库中创建的,我唯一要做的就是声明一个在其中创建套接字的类。我使用的库可以在这里找到:ads.codeplex.com 它用于使用 ads 协议连接到 PLC(在 c# 中的普通套接字之上)
  • 是的,请务必展示您如何使用该 API 库来创建、连接和关闭套接字的代码。然后我们可以为您提供更多帮助。
  • 来自I leave the page,我们应该猜到您使用的是 ASP.NET 吗?或者这是一个 Windows 应用程序?因为如果您正在创建一个 ASP.NET 项目,第一个问题将是知道您何时离开页面... :-)
  • 好的,我确实阅读了此链接ads.codeplex.com/…,并根据他在 API 上使用 Using() 块。因此,当该块的范围结束时,它本身将清理所有打开的套接字。所以就这样使用它。

标签: c# windows-phone-7 garbage-collection destructor idisposable


【解决方案1】:

与 C++ 相比,.NET 不允许显式销毁由垃圾收集器分配的实例(类和装箱值类型/值类型作为通过垃圾收集器分配的类型的实例的成员)。这是因为垃圾收集器会在您认为必要时(定时间隔、内存压力等)在您之后进行清理。如果需要就地释放资源,需要显式调用方法。您可以将此方法命名为 Cleanup。 .NET 已经提供了一个很好采用的模式来做到这一点。方法名称是 Dispose。 (您可以实现具有零参数和 void 返回类型的 Dispose 方法,或者简单地实现 IDisposable 接口。将该方法命名为“Dispose”而不是“Cleanup”可以为您提供更好的工具支持并允许使用“using 语句' 在其中定义应使用实例的范围,并在范围块的末尾自动调用 Dispose 方法。

请参阅http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.71).aspx,了解有关实现 Dispose 方法的详细信息以及如何将其与析构函数(以及固有的垃圾收集器)结合使用的最佳实践

【讨论】:

  • 除了调用方法Dispose,还应该实现IDisposable。如果您的类是可继承的,通常的做法是实现 IDisposable.Dispose(void) 调用受保护的 Dispose(bool) 函数,该函数进行实际处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2013-05-14
  • 2017-10-30
  • 1970-01-01
相关资源
最近更新 更多