A Deterministic Generic Collection

G

Guest

Here is my first attempt at a deterministic collection using Generics,
apologies for C#. I will try to convert to C++/cli.

using System;
using System.Collections.Generic;
using System.Text;

namespace DeterminedGenericCollection
{
// I got tired of copy and pasting IDisposable
// reusable base class
public abstract class Disposable : IDisposable
{
protected bool disposed = false;

// subclass needs to implement these two methods
abstract protected void DisposeManagedResources();
abstract protected void DisposeUnmanagedResources();

public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing) // called from Dispose
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
}
disposed = true;
}
~Disposable() // maps to finalize
{
Dispose(false);
}
}

// generic method to invoke
public interface IInvoke
{
void Invoke();
}

// concrete class to store
class PrintWrapper : Disposable, IDisposable, IInvoke
{
protected override void DisposeManagedResources()
{
//Console.WriteLine("Disposed Managed Resources.");
}
protected override void DisposeUnmanagedResources()
{
Console.WriteLine("Disposed Unmanaged Resources.");
}
public void Invoke()
{
if (disposed) { throw new ObjectDisposedException("Wrapper"); }
// mimic some type of unmanaged action
Console.WriteLine("Print.");
}
}

// generic collection
public class JALGenericCollection<T> : Disposable, IInvoke where T :
IDisposable, IInvoke
{
private readonly object syncLock = new object();
private List<T> list = new List<T>();
public JALGenericCollection() { ;}
// ASSERT d is not null
// ASSERT no object holds a reference to
// d outside of this class
// USAGE Add(new MyClass()); ** newed reference idiom **
// where MyClass implements IDisposable and IInvoke
public void Add(T d)
{
if (d != null)
{
lock (syncLock)
{
list.Add(d);
}
}
else { throw new ArgumentException(); }
}
public void Clear()
{
lock (syncLock)
{
foreach (IDisposable d in list)
{
d.Dispose();
}
list.Clear();
}
}
// return an array of immutable Data struct
public void Invoke()
{
if (disposed) { throw new
ObjectDisposedException("JALGenericCollection"); }
// no one can add or delete during this critical section
lock (syncLock)
{
foreach (IInvoke i in list)
{
i.Invoke();
}
}
}
protected override void DisposeManagedResources()
{
lock (syncLock)
{
foreach (IDisposable d in list)
{
d.Dispose();
}
}
}
protected override void DisposeUnmanagedResources()
{
// do nothing
}
}


class Program
{
static void Main(string[] args)
{
using (JALGenericCollection<PrintWrapper> jalg =
new JALGenericCollection<PrintWrapper>())
{
jalg.Add(new PrintWrapper());
jalg.Add(new PrintWrapper());
jalg.Add(new PrintWrapper());
jalg.Invoke();
jalg.Clear();
jalg.Add(new PrintWrapper());
jalg.Invoke();
//jalg.Add(new InvokeWrapper()); // error,not implement
IDispose
//jalg.Add(new DisposeWrapper()); // error, not implement
IInvoke
}
Console.ReadLine();
}
}
}

Have fun!
 
G

Guest

Here's the C++/CLI version produced with our Instant C++ C# to C++ converter
(your feedback is welcome):

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;

namespace DeterminedGenericCollection
{
// I got tired of copy and pasting IDisposable
// reusable base class
public ref class Disposable abstract: IDisposable
{
public protected:
bool disposed;

// subclass needs to implement these two methods
virtual void DisposeManagedResources() abstract;
virtual void DisposeUnmanagedResources() abstract;

~Disposable()
{
Dispose(true);
GC::SuppressFinalize(this);
}
private:
void Dispose(Boolean disposing)
{
if (!this->disposed)
{
if (disposing) // called from Dispose
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
}
disposed = true;
}
!Disposable() // maps to finalize
{
Dispose(false);
}
};

// generic method to invoke
public interface class IInvoke
{
void Invoke();
};

// concrete class to store
internal ref class PrintWrapper : Disposable, IDisposable, IInvoke
{
public protected:
virtual void DisposeManagedResources() override
{
//Console.WriteLine("Disposed Managed Resources.");
}
virtual void DisposeUnmanagedResources() override
{
Console::WriteLine("Disposed Unmanaged Resources.");
}
public:
void Invoke()
{
if (disposed)
{
throw gcnew
ObjectDisposedException("Wrapper");
}
// mimic some type of unmanaged action
Console::WriteLine("Print.");
}
};

// generic collection
generic<typename T> where T : IDisposable, IInvoke
public ref class JALGenericCollection : Disposable, IInvoke
{
private:
//TODO: INSTANT C++ TODO TASK: C++ does not allow initialization of
non-static fields in their declarations:
initonly Object ^syncLock = gcnew Object^();
//TODO: INSTANT C++ TODO TASK: C++ does not allow initialization of
non-static fields in their declarations:
List<T^> ^list = gcnew List<T^>();
public:
JALGenericCollection()
{
;
}
// ASSERT d is not null
// ASSERT no object holds a reference to
// d outside of this class
// USAGE Add(new MyClass()); ** newed reference idiom **
// where MyClass implements IDisposable and IInvoke
void Add(T ^d)
{
if (d != nullptr)
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
list->Add(d);
}
finally
{

System::Threading::Monitor::Exit(syncLock);
}
}
else
{
throw gcnew ArgumentException();
}
}
void Clear()
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
for each (IDisposable d in list)
{
delete d;
}
list->Clear();
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
// return an array of immutable Data struct
void Invoke()
{
if (disposed)
{
throw gcnew
ObjectDisposedException("JALGenericCollection");
}
// no one can add or delete during this critical
section
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
for each (IInvoke i in list)
{
i->Invoke();
}
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
public protected:
virtual void DisposeManagedResources() override
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
for each (IDisposable d in list)
{
delete d;
}
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
virtual void DisposeUnmanagedResources() override
{
// do nothing
}
};


internal ref class Program
{
static void Main(array<String^> ^args)
{
//INSTANT C++ NOTE: The following 'using' block is replaced by its VC++
equivalent:
// using (JALGenericCollection<PrintWrapper> jalg = new
JALGenericCollection<PrintWrapper>())
JALGenericCollection<PrintWrapper^> ^jalg = gcnew
JALGenericCollection<PrintWrapper^>();
try
{
jalg->Add(gcnew PrintWrapper());
jalg->Add(gcnew PrintWrapper());
jalg->Add(gcnew PrintWrapper());
jalg->Invoke();
jalg->Clear();
jalg->Add(gcnew PrintWrapper());
jalg->Invoke();
//jalg.Add(new InvokeWrapper()); //
error,not implement IDispose
//jalg.Add(new DisposeWrapper()); // error,
not implement IInvoke
}
finally
{
}
Console::ReadLine();
}
};
}

--
David Anton
www.tangiblesoftwaresolutions.com
Instant C#: VB.NET to C# Converter
Instant VB: C# to VB.NET Converter
Instant C++: C# to C++ Converter
Instant J#: VB.NET to J# Converter



JAL said:
Here is my first attempt at a deterministic collection using Generics,
apologies for C#. I will try to convert to C++/cli.

using System;
using System.Collections.Generic;
using System.Text;

namespace DeterminedGenericCollection
{
// I got tired of copy and pasting IDisposable
// reusable base class
public abstract class Disposable : IDisposable
{
protected bool disposed = false;

// subclass needs to implement these two methods
abstract protected void DisposeManagedResources();
abstract protected void DisposeUnmanagedResources();

public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing) // called from Dispose
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
}
disposed = true;
}
~Disposable() // maps to finalize
{
Dispose(false);
}
}

// generic method to invoke
public interface IInvoke
{
void Invoke();
}

// concrete class to store
class PrintWrapper : Disposable, IDisposable, IInvoke
{
protected override void DisposeManagedResources()
{
//Console.WriteLine("Disposed Managed Resources.");
}
protected override void DisposeUnmanagedResources()
{
Console.WriteLine("Disposed Unmanaged Resources.");
}
public void Invoke()
{
if (disposed) { throw new ObjectDisposedException("Wrapper"); }
// mimic some type of unmanaged action
Console.WriteLine("Print.");
}
}

// generic collection
public class JALGenericCollection<T> : Disposable, IInvoke where T :
IDisposable, IInvoke
{
private readonly object syncLock = new object();
private List<T> list = new List<T>();
public JALGenericCollection() { ;}
// ASSERT d is not null
// ASSERT no object holds a reference to
// d outside of this class
// USAGE Add(new MyClass()); ** newed reference idiom **
// where MyClass implements IDisposable and IInvoke
public void Add(T d)
{
if (d != null)
{
lock (syncLock)
{
list.Add(d);
}
}
else { throw new ArgumentException(); }
}
public void Clear()
{
lock (syncLock)
{
foreach (IDisposable d in list)
{
d.Dispose();
}
list.Clear();
}
}
// return an array of immutable Data struct
public void Invoke()
{
if (disposed) { throw new
ObjectDisposedException("JALGenericCollection"); }
// no one can add or delete during this critical section
lock (syncLock)
{
foreach (IInvoke i in list)
{
i.Invoke();
}
}
}
protected override void DisposeManagedResources()
{
lock (syncLock)
{
foreach (IDisposable d in list)
{
d.Dispose();
}
}
}
protected override void DisposeUnmanagedResources()
{
// do nothing
}
}


class Program
{
static void Main(string[] args)
{
using (JALGenericCollection<PrintWrapper> jalg =
new JALGenericCollection<PrintWrapper>())
{
jalg.Add(new PrintWrapper());
jalg.Add(new PrintWrapper());
jalg.Add(new PrintWrapper());
jalg.Invoke();
jalg.Clear();
jalg.Add(new PrintWrapper());
jalg.Invoke();
//jalg.Add(new InvokeWrapper()); // error,not implement
IDispose
//jalg.Add(new DisposeWrapper()); // error, not implement
IInvoke
}
Console.ReadLine();
}
}
}

Have fun!
 
G

Guest

David... Pretty cool. I had to make a few changes as documented below, but it
was helpful! The main logic change is the conversion of using to value
semantics.

// using (JALGenericCollection<PrintWrapper> jalg = new
// JALGenericCollection<PrintWrapper>()) {...} -->

JALGenericCollection<PrintWrapper^> jalg; // converted to value semantics

Here is the updated code:

// DeterminedCPPCollection.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;

namespace DeterminedGenericCollection
{
// I got tired of copy and pasting IDisposable
// reusable base class
public ref class Disposable abstract: IDisposable
{
public protected:
bool disposed;

// subclass needs to implement these two methods
virtual void DisposeManagedResources() abstract;
virtual void DisposeUnmanagedResources() abstract;

~Disposable()
{
_Dispose(true);
GC::SuppressFinalize(this);
}
private:
void _Dispose(Boolean disposing)
{
if (!this->disposed)
{
if (disposing) // called from Dispose
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
}
disposed = true;
}
!Disposable() // maps to finalize
{
_Dispose(false);
}
};

// generic method to invoke
public interface class IInvoke
{
void Invoke();
};

// concrete class to store
public ref class PrintWrapper : Disposable, IDisposable, IInvoke
{
public protected:
virtual void DisposeManagedResources() override
{
//Console.WriteLine("Disposed Managed Resources.");
}
virtual void DisposeUnmanagedResources() override
{
Console::WriteLine("Disposed Unmanaged Resources.");
}
public:
virtual void Invoke() // added virtual
{
if (disposed)
{
throw gcnew ObjectDisposedException("Wrapper");
}
// mimic some type of unmanaged action
Console::WriteLine("Print.");
}
};

// generic collection
generic<typename T> where T : IDisposable, IInvoke
public ref class JALGenericCollection : Disposable, IInvoke // internal ->
public
{
private:
//TODO: INSTANT C++ TODO TASK: C++ does not allow initialization of
// non-static fields in their declarations:
initonly Object ^syncLock;
//TODO: INSTANT C++ TODO TASK: C++ does not allow initialization of
// non-static fields in their declarations:
List<T> ^list; // ^T to T
public:
JALGenericCollection(): syncLock(gcnew Object()), list(gcnew List<T>())
{
;
}
// ASSERT d is not null
// ASSERT no object holds a reference to
// d outside of this class
// USAGE Add(new MyClass()); ** newed reference idiom **
// where MyClass implements IDisposable and IInvoke
void Add(T d) // ^d --> d
{
if (d != nullptr)
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
// equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
if (disposed)
{
throw gcnew ObjectDisposedException("JALGenericCollection");
}
list->Add(d);
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
else
{
throw gcnew ArgumentException();
}
}
void Clear()
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
// equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
if (disposed)
{
throw gcnew ObjectDisposedException("JALGenericCollection");
}
for each (IDisposable^ d in list) // d --> ^d
{
delete d;
}
list->Clear();
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}

virtual void Invoke() // added virtual
{
// no one can add or delete during this critical section
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
// equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
if (disposed)
{
throw gcnew ObjectDisposedException("JALGenericCollection");
}
for each (IInvoke^ i in list) // IInvoke to IInvoke^
{
i->Invoke();
}
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
public protected:
virtual void DisposeManagedResources() override
{
//INSTANT C++ NOTE: The following 'lock' block is replaced by its VC++
// equivalent:
// lock (syncLock)
System::Threading::Monitor::Enter(syncLock);
try
{
for each (IDisposable^ d in list) // IDisposable --> IDisposable^
{
delete d;
}
}
finally
{
System::Threading::Monitor::Exit(syncLock);
}
}
virtual void DisposeUnmanagedResources() override
{
// do nothing
}
};


public ref class Program // internal --> public
{
public: static void Main(array<String^> ^args)
{
//INSTANT C++ NOTE: The following 'using' block is replaced by its VC++
// equivalent:
// using (JALGenericCollection<PrintWrapper> jalg = new
// JALGenericCollection<PrintWrapper>())
JALGenericCollection<PrintWrapper^> jalg; // converted to value semantics
jalg.Add(gcnew PrintWrapper());
jalg.Add(gcnew PrintWrapper());
jalg.Add(gcnew PrintWrapper());
jalg.Invoke();
throw gcnew System::Exception(); // TEST
jalg.Clear();
jalg.Add(gcnew PrintWrapper());
jalg.Invoke();
//jalg.Add(new InvokeWrapper()); // error,not implement IDispose
//jalg.Add(new DisposeWrapper()); // error, not implement IInvoke
}
};
}



int main(array<System::String ^> ^args)
{
try {
DeterminedGenericCollection::program::Main(nullptr);
}
catch(System::Exception^ e) {
Console::WriteLine(e);
}
Console::ReadLine();
}
 
G

Guest

Thanks for your feedback!
We've updated the latest build of Instant C++ to notate the reference types
correctly in "for each" headers. The issue with references to the generic
typename T will require further research (i.e., is T always specified with
value semantics?), but should be addressed soon.

--
David Anton
www.tangiblesoftwaresolutions.com
Instant C#: VB.NET to C# Converter
Instant VB: C# to VB.NET Converter
Instant C++: C# to C++ Converter
Instant J#: VB.NET to J# Converter
 
G

Guest

Hi David... There really is no easy way to convert C# using to C++/cli value
type's exception safe destructor unless you break the using clause into an
anonymous method (available in C++/cli?) or a separate method. So the simple
solution I suppose is what your converter proposes which is:

JALGenericCollection<PrintWrapper^>^ jalg=
gcnew JALGenericCollection<PrintWrapper^>();
try {
jalg->Add(gcnew PrintWrapper());
jalg->Add(gcnew PrintWrapper());
jalg->Add(gcnew PrintWrapper());
jalg->Invoke();
throw gcnew System::Exception(); // TEST
jalg->Clear();
jalg->Add(gcnew PrintWrapper());
jalg->Invoke();
//jalg.Add(new InvokeWrapper()); // error,not implement IDispose
//jalg.Add(new DisposeWrapper()); // error, not implement IInvoke
}
finally {
if (jalg != nullptr) {delete jalg;}
}
 
G

Guest

References to the generic type parameters are now without the 'hat'.
Thanks again for your feedback!
--
David Anton
www.tangiblesoftwaresolutions.com
Instant C#: VB.NET to C# Converter
Instant VB: C# to VB.NET Converter
Instant C++: C# to C++ Converter
Instant J#: VB.NET to J# Converter
 
G

Guest

Oh well, this seems to work also:

if(true) {
JALGenericCollection<PrintWrapper^> jalg;
jalg.Add(gcnew PrintWrapper());
jalg.Add(gcnew PrintWrapper());
jalg.Add(gcnew PrintWrapper());
jalg.Invoke();
throw gcnew System::Exception(); // TEST
jalg.Clear();
jalg.Add(gcnew PrintWrapper());
jalg.Invoke();
}
 
T

Tamas Demjen

David said:
~Disposable()
{
Dispose(true);
GC::SuppressFinalize(this);
}

C++/CLI destructors automtically call SuppressFinalize. Only very early
(Beta 1) C++/CLI compilers required us to manually call SupressFinalize.
It would be very counter intuitive to do this manually for every single
destructor. Of course it doesn't do any harm to duplicate it.

Also, C++/CLI compilers automatically create Dispose(bool), so you don't
have to write that either. A C++/CLI destructor is equivalent with this:

public:
virtual void Dispose() sealed {
this->Dispose(true);
System::GC::SuppressFinalize(this);
}

Tom
 
G

Guest

I agree - but for a conversion from C#, I think it's safer to include the
equivalent, even though redundant, elements.
--
David Anton
www.tangiblesoftwaresolutions.com
Instant C#: VB.NET to C# Converter
Instant VB: C# to VB.NET Converter
Instant C++: C# to C++ Converter
Instant J#: VB.NET to J# Converter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top