Reputation: 1470
I have run into a small issue in my program. I have a class with a Socket in it and some declared variables.
Now when i leave the page where the class was defined,
Class someclass = new class;
I want the class to be "destroyed", So that I can open a new socket with the same port/ip on a other page. (now the port and ip adress seems to be locked with the class i don't deconstruct/dispose/g.c)
Because I have a c++ background, and this is my first time using c#. I have no clue where to start, because in c++ you just call the destructor. This wil clean up your class and remove all active sockets/variables. But how do i accomplish this in c#. I have read some stuff about the Idisposable class but that doesn't make things clearer. Also there's the garbage collector and normal deconstructor. I don't know what to use, and more important how to use it.
Edit 1
As said below in the comments: this project is a windows phone project, that uses a external library for creating a socket and setting up communication between the windows phone and a Beckhoff PLC.
I've created an extra layer on top of the original library to make my variables easier to declare. the extra layer look likes this:
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());
}
}
}
/* Noticed the : IDisposable thats because i have allready tried to implement it, but that didn't work well. */
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;
}
}
}
In the code below i declare my " twincat variables" which i connect to a datachange event. Also, these are connected to a " .name" variable on the plc.
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");
}
}
}
And last but not least. In the " code behind the page" (mainpage.xaml.cs) I make an instance of the MainViewModel and set it to datacontext for binding.
private MainPageViewModel _MV;
_MV = new MainPageViewModel();
Device_listbox.DataContext = _MV.DeviceList;
I hope this helps so you guys can help me :)
Upvotes: 0
Views: 1918
Reputation: 15130
In contrast to C++, .NET doesn't allow the explicit destruction of an instance allocated by the garbage collector (classes and boxed value types/value types as members of an instance of a type allocated through the garbage collector). This because the Garbage Collector takes care of cleaning up after you when it deems nessesary (timed interval, memory pressure etc). If you need to release resources at the spot, you need to explicitly call a method. You can name this method something like Cleanup. .NET already comes with a well adopted pattern to do so. The method name is Dispose. (You c an implement a Dispose method with zero parameters and a void return type, or simply implement the IDisposable interface. Naming the method as 'Dispose' rather than 'Cleanup' gives you better tooling support and allows the use of the 'using statement' in which you define the scope wherein your instance should be used and which automatically calls the Dispose method at the end of the scope block.
Please see http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.71).aspx for detailed information on implementing the Dispose method and a best practice of how to use it in combination with a Destructor (and inherently the garbage collector)
Upvotes: 3