singleton ienumerable, need to add more...

D

David

Hi all,

I have a singleton ienumerable that collects data from a database. I have
listed the code below. It has the usual methods of current, move and reset.

I need to go to a certain position or set filters or many other things and I
don't know how to do this. I have just learned singleton AND ienumerable, so
miraculously got this to work so far. I could do with a bit of help to go
further with it. If need by, I may have to change the type to achieve the
aim.

What I want to do next is to select a specific row by passing in an index. I
don't know how to do this at all and no matter what I try, I just can't
compile.

My source is below...

All help is appreciated.


public class Folders : System.Collections.IEnumerable,
System.Collections.IEnumerator
{
private static Folders mObj; // This is used to manage the singleton.
private DataTable DT;

System.Collections.IEnumerator ienum;

// This is the singleton constructor
private Folders()
{
InitData();
}

// This sets up the singleton.
public static Folders SiteFolders
{
get
{
if(mObj == null) // only one instance is created
mObj = new Folders();

return mObj;
}
}

private void InitData()
{

// Get my data from the database and pass into ienum
ienum = DT.Rows.GetEnumerator();

}

public System.Collections.IEnumerator GetEnumerator()
{

// Polymorph this object into an IEnumerator interface
return (System.Collections.IEnumerator)this;

}

public void Reset()
{
ienum.Reset();
}

public bool MoveNext()
{
return ienum.MoveNext();
}

public object Current
{
get
{
return new Folder((DataRow)ienum.Current);
}
}
#endregion

public object SelectFolder(int myRow)
{
// get
// {
return new Folder((DataRow)myRow);
// }
}

}


I have tried using square brackets for the selectfolder as well, but just
won't compile. How can I select a specific row? Incidentally, the Folder
that selectfolder is referencing just takes my datatable and passes it into
some properties.

Because I have just learned about the singleton and ienumerable, I really do
not know how to continue. :-(

Best regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Local franchises available
 
M

Marc Gravell

OK, one thing at a time.

I think the "indexer" syntax you are looking for is:

public Folder this[int rowIndex]
{
get
{
return new Folder(DT.Rows[rowIndex]);
}
}

you can then access Folders.SiteFolders[4]; (etc)

Note that I tweaked the return type to be useful. However, the bigger
points:

* it is unusual for something to be enumerable and an enumerator; I
suspect you just mean IEnumerable or IEnumerable<Folder>
* Thread safety: since you appear new to C# this probably won't be an
issue, but in general static methods should be thread safe, which
SiteFolders isn't
* could just pass up the obtained enumerator, rather than the
smoke'n'mirrors?
* each call to Current returns a different object; this could get very,
very confusing, and lead to all sorts of fun
* minor comment issue: this is merely a cast, not polymorphism
* not sure this is really suited to a singleton pattern - although that
might just be that I don't know enough about the context, so I'll give
you the benefit of the doubt

Given that you seem to have a wrapper object (Folder), there may be a
lot of benefit in moving to a List<Folder> implementation; this would
allow you to hand over a simple enumerator without all the fuss, and
your Folder objects would only exist once each- you'd just loop over
the DataTable.


Let me know if you want more help,

Marc
 
G

Guest

Thank you Marc,

The initial enumerable info I found on the net somewhere, as also the
singleton.

I have had quite a battle to get them both to work,

My background is classic ASP, having moved into .net a couple of years ago,
but still having large gaps in my knowledge.

I did try something similar to the public Folder this[int rowIndex] but kept
getting errors. However, I don't think I had the "this" word. I will try that.

For your points...
1. I assume this is with the two items that the class is derived from. Can I
just remove the IEnumerable and it will work?
2. At the moment, thread safety is not an issue, but is likely to be as the
project progresses. How should I write it to be safe?
3. (Pass the obtoned enumerator) Can you give me some pointers? code
examples or URLs?
4. Again, this was just copied. I understand that an ienumerable has to have
a min of 3 items. reset, movenext and current. What should I be doing here?
5. polymorph... This is a direct copy. Having not covered polymorphing, I
couldn't really question this, though I can quite clearly see (now you
mention it) that it is a cast.
6. I have had a 24 message thread in aspnet trying to acheive this. What I
am wanting is a "global" datatable that is enumerated. I want to be able to
just simply assign a variable without having the "new" operator. An example...

I wanted to have the folders loaded from the database. I DID NOT want to
have to go to the database every time, as a DB call is expensive.

I wanted all my controls, Page, UserControls and Custom Controls to be able
to call the same instance of data. Having a "new" operator would instantiate
the data each time, thereby calling the database each time. If you are
familiar with Microsoft CMS, I want to do something like...

Channels MyChannels = CmsHttpContext.Current.Channel.Channels;

foeach (Channel ch in MyChannels)
{
Response.Write ch.DisplayName;
}

WantedChannel = MyChannels.Channel.GetByGuid("guid-string");

Notice, no "new".

Thank you.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available


Marc Gravell said:
OK, one thing at a time.

I think the "indexer" syntax you are looking for is:

public Folder this[int rowIndex]
{
get
{
return new Folder(DT.Rows[rowIndex]);
}
}

you can then access Folders.SiteFolders[4]; (etc)

Note that I tweaked the return type to be useful. However, the bigger
points:

* it is unusual for something to be enumerable and an enumerator; I
suspect you just mean IEnumerable or IEnumerable<Folder>
* Thread safety: since you appear new to C# this probably won't be an
issue, but in general static methods should be thread safe, which
SiteFolders isn't
* could just pass up the obtained enumerator, rather than the
smoke'n'mirrors?
* each call to Current returns a different object; this could get very,
very confusing, and lead to all sorts of fun
* minor comment issue: this is merely a cast, not polymorphism
* not sure this is really suited to a singleton pattern - although that
might just be that I don't know enough about the context, so I'll give
you the benefit of the doubt

Given that you seem to have a wrapper object (Folder), there may be a
lot of benefit in moving to a List<Folder> implementation; this would
allow you to hand over a simple enumerator without all the fuss, and
your Folder objects would only exist once each- you'd just loop over
the DataTable.


Let me know if you want more help,

Marc
 
G

Guest

Thank you Marc,

The initial enumerable info I found on the net somewhere, as also the
singleton.

I have had quite a battle to get them both to work,

My background is classic ASP, having moved into .net a couple of years ago,
but still having large gaps in my knowledge.

I did try something similar to the public Folder this[int rowIndex] but kept
getting errors. However, I don't think I had the "this" word. I will try that.

For your points...
1. I assume this is with the two items that the class is derived from. Can I
just remove the IEnumerable and it will work?
2. At the moment, thread safety is not an issue, but is likely to be as the
project progresses. How should I write it to be safe?
3. (Pass the obtoned enumerator) Can you give me some pointers? code
examples or URLs?
4. Again, this was just copied. I understand that an ienumerable has to have
a min of 3 items. reset, movenext and current. What should I be doing here?
5. polymorph... This is a direct copy. Having not covered polymorphing, I
couldn't really question this, though I can quite clearly see (now you
mention it) that it is a cast.
6. I have had a 24 message thread in aspnet trying to acheive this. What I
am wanting is a "global" datatable that is enumerated. I want to be able to
just simply assign a variable without having the "new" operator. An example...

I wanted to have the folders loaded from the database. I DID NOT want to
have to go to the database every time, as a DB call is expensive.

I wanted all my controls, Page, UserControls and Custom Controls to be able
to call the same instance of data. Having a "new" operator would instantiate
the data each time, thereby calling the database each time. If you are
familiar with Microsoft CMS, I want to do something like...

Channels MyChannels = CmsHttpContext.Current.Channel.Channels;

foeach (Channel ch in MyChannels)
{
Response.Write ch.DisplayName;
}

WantedChannel = MyChannels.Channel.GetByGuid("guid-string");

Notice, no "new".

Thank you.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available


Marc Gravell said:
OK, one thing at a time.

I think the "indexer" syntax you are looking for is:

public Folder this[int rowIndex]
{
get
{
return new Folder(DT.Rows[rowIndex]);
}
}

you can then access Folders.SiteFolders[4]; (etc)

Note that I tweaked the return type to be useful. However, the bigger
points:

* it is unusual for something to be enumerable and an enumerator; I
suspect you just mean IEnumerable or IEnumerable<Folder>
* Thread safety: since you appear new to C# this probably won't be an
issue, but in general static methods should be thread safe, which
SiteFolders isn't
* could just pass up the obtained enumerator, rather than the
smoke'n'mirrors?
* each call to Current returns a different object; this could get very,
very confusing, and lead to all sorts of fun
* minor comment issue: this is merely a cast, not polymorphism
* not sure this is really suited to a singleton pattern - although that
might just be that I don't know enough about the context, so I'll give
you the benefit of the doubt

Given that you seem to have a wrapper object (Folder), there may be a
lot of benefit in moving to a List<Folder> implementation; this would
allow you to hand over a simple enumerator without all the fuss, and
your Folder objects would only exist once each- you'd just loop over
the DataTable.


Let me know if you want more help,

Marc
 
M

Marc Gravell

1. Actually I think it is IEnumerator that is unnecessary / confusing
matters

2. Either you need a static lock variable somewhere, or alternatively you
could simply take the hit and initialise the field in the static ctor (which
is thread-safe by the CLR). Jon discusses the various singleton creation
approaches here:
http://www.yoda.arachsys.com/csharp/singleton.html

3: (see 4)
4: no IEnumerator has those members; IEnumerable has GetEnumerator. However,
your code doesn't really (seem to) expose the DataTable implementation very
much - it just exposes the Folder class; so I would do something like (in
pseudo#):

// static field
static readonly List<Folder> folders;

// static ctor
// after initialising DT
folders = new List<Folder>();
foreach(table-row in DT) {
folders.Add(new Folder(table-row));
}
folders.TrimExcess(); // or possibly use ToArray and just store the Folder[]

// GetEnumerator()
return folders.GetEnumerator();

// iterator
return folders[index];

etc

I would also implement IEnumerable<Folder>, not IEnumerable and not
IEnumerator

5: fair enough
6: context is everything; that seems reasonable

re CMS: I haven't used CMS; this looks to be related to the http-context
(such as the current user), so it isn't *purely* static. I'm guessing that
they are caching the details per-user in session-state or some other cache.
As long as your collection doesn't change per user your approach should be
fine.

Marc
 
G

Guest

Thanks Marc,

I will have a go at implementing this.

re: the CMS stuff, I have been able to update the collection sort of
dynamically. In this case, it is a list of folders from the database (sort of
virtual folders, no file system folders though). Only admins will add new
folders. On their page, when a new folder is submitted, I can update the
datatable. I wonder if this is why the class may not be thread safe.

You are correct with the http-context. I am still getting used to this.
Something else I want to do (which I will learn sometime soon) is getting all
the dotted lines, and geting parent items etc. such as...

CmsHTTPContext.Current.Channel.Parent.Parent.Parent.Url

(I need to do things like...
1. Find the current channel.
2. find the parent channel (recursive it needed)
3. find the URL.
all 3 items can be independent, which means I can stop at any point in the
chain above)

All these will need to be put into my project, but I can refactor my code
later when I learn this.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
M

Marc Gravell

My original "thread safe" comment related to the fact that if 2 callers
invoked the static getter at the same time, and both get past the ==null
check, then you could theoretically get two instances of the singleton. Very
unlikely, but technically possible. In reality you would have to push hard
to invoke this, as it only ever changes once per app-domain.

However: if you are allowing people to insert into the DT, then you have a
whole other set of problems... enumerators are usually not fans of the data
changing, so if an admin adds a folder to your static object while another
user is enumerating (foreach), then the latter will burn. You would
generallly want to protect multiple adds using a lock. Depending the
scenario, a ReaderWriterLock may be in order here (if writes are very rare,
and you want simultaneous reads), but to avoid the problem above you would
have to lock the collection (read lock) every time you enumerate it.

Rather than expect the client to do this work, another option is to provide
a method that does the readlock, pushes the data into an array (.ToArray()
using List<T>), and returns the array as a standalone snapshot - this is
then uaffected by other threads, and the caller can enumerate it (or use the
indexer) at their leisure - i.e.

public static Folder[] GetFolders() {
Folder[] result;
// TODO: get read lock; see ReaderWriterLock on MSDN2
result = folders.ToArray();
// TODO: release read lock
return result;
}

public static void AddFolder(Folder folder) {
// TODO: get write lock
folders.Add(folder);
// TODO: release write lock
}

With this model, you aslo don't implement IEnumerable or IEnumerable<T>, as
the client should enumerate the standalone array, not the more sensitive
inner colllection.

Marc
 
G

Guest

Hi Marc,

I am trying to follow you on all this, starting from your first response. My
aim is to draw as much knowledge as I can for future use as well, even if it
is not in the final implementation of my current aim.

In your first response, you have told me how to set up an indexable folder.
After a bit of tinkering, I have this working. I was missing things, but it
works now. Thank you.

With your comment about enumerable and enumerator, I followed your next
message in the thread and removed IEnumerator from my class definition. I
then got an invalid cast. This is on the GetEnumerator function. I have not
made any changes (yet) to the cast, as I am not sure what to put here. I have
tried changing to IEnumerable and also my ienum to IEnumerable but I get more
build errors.

Continuing on...
With this failure, I tried to continue with your second message and create
the static field List<Folder> but got red squiggly underlines, so could not
continue with that as this is also new territory. :-( I did a search and
found that it should follow the lines of... List<Folder>SomethingHere folders;

Your // GetEnumerator() is that a function I need to put that in? Is that
the GetEnumerator function I refer to earlier?

Again for // iterator???

The two functions in your last message, public static Folder[] GetFolders()
and public static void AddFolder(Folder folder)...

Am I to assume that they should be in my Folder class not my Folders class?
Also, the last statement, I don't really understand...

Thank you for your time.

Regards,
Dave Colliver.
http://www.SheffieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available


Marc Gravell said:
My original "thread safe" comment related to the fact that if 2 callers
invoked the static getter at the same time, and both get past the ==null
check, then you could theoretically get two instances of the singleton. Very
unlikely, but technically possible. In reality you would have to push hard
to invoke this, as it only ever changes once per app-domain.

However: if you are allowing people to insert into the DT, then you have a
whole other set of problems... enumerators are usually not fans of the data
changing, so if an admin adds a folder to your static object while another
user is enumerating (foreach), then the latter will burn. You would
generallly want to protect multiple adds using a lock. Depending the
scenario, a ReaderWriterLock may be in order here (if writes are very rare,
and you want simultaneous reads), but to avoid the problem above you would
have to lock the collection (read lock) every time you enumerate it.

Rather than expect the client to do this work, another option is to provide
a method that does the readlock, pushes the data into an array (.ToArray()
using List<T>), and returns the array as a standalone snapshot - this is
then uaffected by other threads, and the caller can enumerate it (or use the
indexer) at their leisure - i.e.

public static Folder[] GetFolders() {
Folder[] result;
// TODO: get read lock; see ReaderWriterLock on MSDN2
result = folders.ToArray();
// TODO: release read lock
return result;
}

public static void AddFolder(Folder folder) {
// TODO: get write lock
folders.Add(folder);
// TODO: release write lock
}

With this model, you aslo don't implement IEnumerable or IEnumerable<T>, as
the client should enumerate the standalone array, not the more sensitive
inner colllection.

Marc
 
M

Marc Gravell

What runtime are you using? 1.1? 2.0? List<T> is 2.0 generics, and requires
the System.Collections.Generic namespace.

As for the rest of it - my opinion is that you are making all of this a lot
more complicated than it needs to be...
this would be the entire of my code for this; it allows the caller to get
the set of folders (GetFolders()), which they can then enumerate or use the
indexer on. It allows an admin to add folders. And it lets it all work at
once correctly (ReaderWriterLock).

Marc

using System;
using System.Collections.Generic;
using System.Threading;

public class Folder {
public Folder(object obj) {
// TODO: whatever goes here (not shown in your code)
}
}
public static class Folders
{
private static readonly List<Folder> folders;
private static readonly ReaderWriterLock syncLock = new
ReaderWriterLock();
static Folders()
{
folders = new List<Folder>();
//TODO; replace with actual code to initialise from DB
foreach (object obj in new object[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })
{
folders.Add(new Folder(obj));
}
folders.TrimExcess();
}
public static Folder[] GetFolders()
{
syncLock.AcquireReaderLock(Timeout.Infinite);
try
{
return folders.ToArray();
}
finally
{
syncLock.ReleaseReaderLock();
}
}
public static void AddFolder(Folder folder)
{
syncLock.AcquireWriterLock(Timeout.Infinite);
try
{
folders.Add(folder);
}
finally
{
syncLock.ReleaseWriterLock();
}
}
}
 
D

David

Hi Marc,

(I am writing for ASP.NET)

I have modifed this to use an arraylist as, as you say, List is not part of
..NET 1.1 In the Folder class, all that was in there was setting properties
from a datarow. Nothing special.

With that, I changed object obj to DataRow dr, though that may cause me a
problem. I am not sure yet.

Below is my class. I had to wrap a namespace around the class. I amstill
having a few problems with it. (I really do apologise for not having enough
knowledge in this area to fix it myself. I have spent hours on it now, got
some areas fixed (sort of), but not others. :-( )

Other things I had to fix due to differences in 1.1 and 2, however, not
sure if I have fixed them correctly.
1. Can't have a static class, so have removed "static".
2. List<> made to an ArrayList. (Mentioned above)
3. in the folders.Add inside the Folders constructor, I have passed a
DataRow. I can't see why this would be any different.
4. folders.TrimToSize() instead of TimeExcess()

If I have made bad assumptions/adjustments, please tell me. All part of the
learning process.

The problem at the moment is in the public static Folder[] GetFolders(). I
was getting cannot implicitly convert object[] to folders.ToArray(), so I
tried a number of things to cast the object, eventually getting (Folder[])
to compile. However, when I run it, I am getting Specified cast is not
valid.

public class Folders
{
//private static readonly List<Folder> folders;
private static readonly ArrayList folders;
private static readonly ReaderWriterLock syncLock = new
ReaderWriterLock();

static Folders()
{
//folders = new List<Folder>();
folders = new ArrayList();
//TODO; replace with actual code to initialise from DB

DataAccessLayer.DataManager DM = new DataAccessLayer.DataManager();
DataTable DT = DM.FolderList();

//foreach (object obj in new object[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })
foreach (DataRow dr in DT.Rows)
{
folders.Add(new Folder(dr));
}
//folders.TrimExcess();
folders.TrimToSize();
}

public static Folder[] GetFolders()
{
syncLock.AcquireReaderLock(Timeout.Infinite);
try
{
return (Folder[])folders.ToArray();
}
finally
{
syncLock.ReleaseReaderLock();
}
}

public static void AddFolder(Folder folder)
{
syncLock.AcquireWriterLock(Timeout.Infinite);
try
{
folders.Add(folder);
}
finally
{
syncLock.ReleaseWriterLock();
}
}
}

Something else I am looking at, though not sure yet how it will work... is
your AddFolder. The way I think it works is to add a single line. What I
would like to do is to re-run my database query and repopulate the folder
list from scratch. I can probably work this out for myself though. I will
also be wanting to be able to filter the folders based on certain criteria,
such as FolderID = ParentFolderID, again, I should be able to work this out.

Something that I am not sure about though as I can't work it out (though am
partway there) is how to read it the way I have demonstrated with the
Microsoft CMS sample. I am doing it this way...

Folder[] MyFolders = Folders.GetFolders();

foreach (Folder FD in MyFolders)
{
Response.Write(FD.FolderID.ToString());
Response.Write(FD.FolderName);
}

Whilst it is not the way I would have liked, I can live with it. If you know
of another way (I know I can change the MyFolders in the foreach to
Folders.GetFolders()) I would appreciate the knowledge.

Something else I am not sure yet (as I can't get it to run properly) is that
because I have removed the static modifier from the class, will that cause
the database to be called each time? This is the main criteria for the
class. The other was to not have to use the "new" when instantiating the
class.

One final question. This is about the difference between 1.1 and 2. The
List<>, what exactly is the difference between List and ArrayList and why
use List over ArrayList?

Thanks for your help.

Best regards,
Dave Colliver.
http://www.ManchesterFOCUS.com
~~
http://www.FOCUSPortals.com - Local franchises available


Marc Gravell said:
What runtime are you using? 1.1? 2.0? List<T> is 2.0 generics, and
requires the System.Collections.Generic namespace.

As for the rest of it - my opinion is that you are making all of this a
lot more complicated than it needs to be...
this would be the entire of my code for this; it allows the caller to get
the set of folders (GetFolders()), which they can then enumerate or use
the indexer on. It allows an admin to add folders. And it lets it all work
at once correctly (ReaderWriterLock).

Marc

using System;
using System.Collections.Generic;
using System.Threading;

public class Folder {
public Folder(object obj) {
// TODO: whatever goes here (not shown in your code)
}
}
public static class Folders
{
private static readonly List<Folder> folders;
private static readonly ReaderWriterLock syncLock = new
ReaderWriterLock();
static Folders()
{
folders = new List<Folder>();
//TODO; replace with actual code to initialise from DB
foreach (object obj in new object[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })
{
folders.Add(new Folder(obj));
}
folders.TrimExcess();
}
public static Folder[] GetFolders()
{
syncLock.AcquireReaderLock(Timeout.Infinite);
try
{
return folders.ToArray();
}
finally
{
syncLock.ReleaseReaderLock();
}
}
public static void AddFolder(Folder folder)
{
syncLock.AcquireWriterLock(Timeout.Infinite);
try
{
folders.Add(folder);
}
finally
{
syncLock.ReleaseWriterLock();
}
}
}
 
M

Marc Gravell

obj to DataRow dr
Good call; my "obj" was just a sampl - your code made it clear that
there was a ctor, but it wasn't shown, so I "failed safe"
I really do apologise for not having enough
knowledge in this area to fix it myself
No need to; the only way to obtain useful knowledge is to try things,
and you are showing that you *are* giving it a good go, so no apology.
Sometimes people post what amounts to "please do everything; I haven't
even tried"; you have given it fair effort.
1. static class
It will work identically without it; "static class" is just a handy way
of ensuring static semantics at the compiler level, but this can be
done with or without this new modifier
2. ArrayList, 3. ctor, 4. TrimToSize
Perfect

The array cast is unfortunately expected when using an ArrayList. There
is an overload to enable this cast:
return (Folder[])folders.ToArray(typeof(Folder));
rerun query etc
Fine, but for performance I would run the query first (getting the DT),
and then (once complete) take out the write-lock and update the
collection (probably Clear() and re-build from scratch)
foreach question
The nuicance is supporing the writer in a threaded environment (such as
ASP.NET; *highly* threaded); there are a few tricks, but I think that
they may be a little more troublesome long-term; personally, if I only
needed the data once (i.e. I don't need to loop 3 times), then I would
just use foreach(Folder folder in Folders.GetFolders()) {}.
List vs ArrayList
List<T> (not List) is a generic collection type; this means that it is
stronlgy-typed using a template type "T" (that is only decided by the
programmer later): List<Folder> knows that it is means to hold Folder
items, where-as ArrayList only knows about "object". Firstly this makes
it very easy (and safe) to use; as examples, ToArray() returns
Folder[], and folders[0] would return a Folder. It also means that you
cannot *possibly* add an incorrect typed object (such as a string). For
value-types this also avoids boxing etc, making it more efficient.

Marc
 
D

David

Hi Marc,

I appear at the moment to be taking a lot of knowledge, to the point where
you gave me the sample code. I felt a little guilty about this, however it
has really helped me along and I have learned one or two things along the
way and it is appreciated.

If I was to rerun the query again, you say to take out the Write Lock. How
would I do that?

I have overloaded the GetFolders method as I want to be able to just do
GetFolders (which would select top level parent), then select specifically
child folders of that parent, so that if need be, I can set up a recursive
loop. This appears to work excellent, but I would like you to cast your eye
over it and tell me if I am missing something, or have made an inefficient
mistake.

public static Folder[] GetFolders()
{
return GetFolders(0);
}

public static Folder[] GetFolders(int ParentFolderID)
{

DataTable ChildDT = DT.Copy(); // This line took me a while to work. I
was doing .Clone() but nothing was happening.
DataRow[] RowView = ChildDT.Select("FolderParent=" + ParentFolderID);

ArrayList ChildFolders = new ArrayList();

foreach (DataRow dr in RowView)
{
ChildFolders.Add(new Folder(dr));
}
ChildFolders.TrimToSize();

syncLock.AcquireReaderLock(Timeout.Infinite);
try
{
return (Folder[])ChildFolders.ToArray(typeof(Folder));
}
finally
{
syncLock.ReleaseReaderLock();
}
}

The only thing I can think of is that I am populating the arraylist quite
early on in the previous code, but with this new method, never getting a
chance to read it... Also, do I need to move the syncLock anywhere in the
GetFolders overload? In fact, as I am creating a new arraylist that will
only be around just for that instance, do I even need the syncLock?

When I am happy with this, then I can do the "ParentFolder" using a similar
method.

Would this code be quite easy to do something like...

GetFolders.GetFolders.GetFolders.GetFolders ? (the point being to try and
get the Great Grandchildren of the current folder... I have some sample
code somewhere to do the multiple dotted thing, so I will see if that can
easily be added.)

Once again, thanks for your help.

Best regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Local franchises available


Marc Gravell said:
obj to DataRow dr
Good call; my "obj" was just a sampl - your code made it clear that
there was a ctor, but it wasn't shown, so I "failed safe"
I really do apologise for not having enough
knowledge in this area to fix it myself
No need to; the only way to obtain useful knowledge is to try things,
and you are showing that you *are* giving it a good go, so no apology.
Sometimes people post what amounts to "please do everything; I haven't
even tried"; you have given it fair effort.
1. static class
It will work identically without it; "static class" is just a handy way
of ensuring static semantics at the compiler level, but this can be
done with or without this new modifier
2. ArrayList, 3. ctor, 4. TrimToSize
Perfect

The array cast is unfortunately expected when using an ArrayList. There
is an overload to enable this cast:
return (Folder[])folders.ToArray(typeof(Folder));
rerun query etc
Fine, but for performance I would run the query first (getting the DT),
and then (once complete) take out the write-lock and update the
collection (probably Clear() and re-build from scratch)
foreach question
The nuicance is supporing the writer in a threaded environment (such as
ASP.NET; *highly* threaded); there are a few tricks, but I think that
they may be a little more troublesome long-term; personally, if I only
needed the data once (i.e. I don't need to loop 3 times), then I would
just use foreach(Folder folder in Folders.GetFolders()) {}.
List vs ArrayList
List<T> (not List) is a generic collection type; this means that it is
stronlgy-typed using a template type "T" (that is only decided by the
programmer later): List<Folder> knows that it is means to hold Folder
items, where-as ArrayList only knows about "object". Firstly this makes
it very easy (and safe) to use; as examples, ToArray() returns
Folder[], and folders[0] would return a Folder. It also means that you
cannot *possibly* add an incorrect typed object (such as a string). For
value-types this also avoids boxing etc, making it more efficient.

Marc
 
M

Marc Gravell

Actually, the lock should probably be around the .Copy() code; the
purpose of this is to ensure that if you have somebody reading the
folders while an admin pushes the "update" button, then it all works
correctly, i.e. if you have the read lock, it prevents the admin lock
being taken until you have finished the Copy(); likewise, if the admin
has started work it keeps the readers at bay for a few milliseconds.

I must admin I wasn't entire clear about your dotted parent suggestion
- i.e. I couldn't tell enough to comment much.

Re the "parent id" stuff, there may be a few things you could do with
hashtable (Dictionary in 2.0), but I would keep it simple for now ;-p

Marc
 

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