|
Yes, that's what I imagined would work in your situation.
|
|
|
|
|
An enumerator has a state ("where am I?") which must be saved somewhere. If its state is inside the collection itself, you probably can't have two independent iterators at once, so things like:
foreach(someType a in collection) {
foreach (someType b in collection) {
if (a!=b) doSomeThingTo(a,b);
}
}
would fail. Having code accessing your collection from different threads through enumerators would fail too.
What I'm saying is, most of the time, IEnumerable (i.e. GetEnumerator ) requires you to create a new enumerator each time. It is too bad they called it such, CreateEnumerator would have been the better choice.
PS, FWIW: are you familiar with AsReadOnly?[^]
|
|
|
|
|
Good point Luc, thanks. I will look into this further.
Luc Pattyn wrote: FWIW: are you familiar with AsReadOnly?
Yes I am. The collections need to have internal constructors and an internal Add method so it was just as easy to create a simple base class (not the MyBase referred to in the OP) with this functionality that the other collections derive from.
|
|
|
|
|
Hi Davey,
If you did not use IList(s) (as Luc suggested) set to some Collection modified by the 'ReadOnly() method, as in:
public static IList<MyFoo> MyFoos;
MyFoos = MyFooCollection.AsReadOnly(); Then I am very curious what technique(s) you did use to make the Collections in your code ReadOnly.
thanks, Davey (and Luc)
When I consider the brief span of my life, swallowed up in the eternity before and after, the little space which I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which knows me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then. Blaise Pascal
|
|
|
|
|
Well a simple collection (generic) that is immutable (so naturally read only) just needs to accept items at instanciation, optionaly an indexer with a getter only defined and a count property - and of course implemeting IEnumerable<T> so it can be enumerated. Therefore a simple wrapper around List<T> suffices:
public class ImmutableCollection<T> : IEnumerable<T>
{
private List<T> innerList;
public ImmutableCollection(IEnumerable<T> collection)
{
innerList = new List<T>(collection);
}
public T this[int index]
{
get { return innerList[index]; }
}
public int Count
{
get { return innerList.Count; }
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)innerList).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)innerList).GetEnumerator();
}
}
As the innerList is never exposed it is read only
Usage:
ImmutableCollection<string> collection = new ImmutableCollection<string>(new string[] { "A", "B", "C" });
Of course, the properties/fields of the the items contained will not be immutable, but that is the same as the ReadOnlyCollection<T> available from .AsReadOnly , but the minimum functionality only is exposed, and whatever you need to add can be created simply by accessing the inner list.
If necessary, the inner list could be made protected so it can be accessed directly in derived classes where concrete classes are desired or required.
|
|
|
|
|
+5 Thanks for this most enlightening answer !
When I consider the brief span of my life, swallowed up in the eternity before and after, the little space which I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which knows me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then. Blaise Pascal
|
|
|
|
|
encapsulation
|
|
|
|
|
How about getting the enumerator of each collection to enumerate both of them?
I have knocked up an example of the general outline of my classes, I have used this in the MyFooMyBarPool.MyBases property.
using System;
using System.Collections;
using System.Collections.Generic;
public enum BaseType
{
MyFoo,
MyBar
}
public abstract class MyBase
{
private BaseType baseType;
private string name;
internal MyBase(BaseType baseType, string name)
{
this.baseType = baseType;
this.name = name;
}
public string Name
{
get { return name; }
}
public override string ToString()
{
return string.Format("Type: {0}, Name: {1}", baseType, name);
}
}
public sealed class MyFoo : MyBase
{
internal MyFoo(string name)
: base(BaseType.MyFoo, name)
{ }
}
public sealed class MyBar : MyBase
{
internal MyBar(string name)
: base(BaseType.MyBar, name)
{ }
}
public class SimpleCollection<T> : IEnumerable<T>
{
private List<T> innerList;
public SimpleCollection(IEnumerable<T> items)
{
innerList = new List<T>(items);
}
public T this[int index]
{
get { return innerList[index]; }
}
public int Count
{
get { return innerList.Count; }
}
public IEnumerator<T> GetEnumerator()
{
return innerList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return innerList.GetEnumerator();
}
}
public class MyFooCollection : SimpleCollection<MyFoo>
{
internal MyFooCollection(IEnumerable<MyFoo> myFoos)
: base(myFoos)
{ }
}
public class MyBarCollection : SimpleCollection<MyBar>
{
internal MyBarCollection(IEnumerable<MyBar> myBars)
: base(myBars)
{ }
}
public class MyFooMyBarPool
{
private MyFooCollection myFooCollection;
private MyBarCollection myBarCollection;
public MyFooMyBarPool()
{
myFooCollection = new MyFooCollection(new MyFoo[] { new MyFoo("A"), new MyFoo("B"), new MyFoo("C") });
myBarCollection = new MyBarCollection(new MyBar[] { new MyBar("A"), new MyBar("B"), new MyBar("C") });
}
public IEnumerable<MyBase> MyBases
{
get
{
IEnumerator<MyFoo> myFooEnumerator = myFooCollection.GetEnumerator();
while (myFooEnumerator.MoveNext())
yield return myFooEnumerator.Current;
IEnumerator<MyBar> myBarEnumerator = myBarCollection.GetEnumerator();
while (myBarEnumerator.MoveNext())
yield return myBarEnumerator.Current;
yield break;
}
}
public MyFooCollection MyFoos
{
get { return myFooCollection; }
}
public MyFooCollection MyBars
{
get { return myFooCollection; }
}
}
class Program
{
static void Main(string[] args)
{
MyFooMyBarPool pool = new MyFooMyBarPool();
foreach (MyBase myBase in pool.MyBases)
Console.WriteLine(myBase);
Console.WriteLine(
"{0} MyFoo and {1} MyBar items",
pool.MyFoos.Count, pool.MyBars.Count);
Console.ReadKey();
}
}
|
|
|
|
|
Sorry Dave, it's too early a day to study all that in any detail. As I didn't see any new or Create in there (I may have overlooked them), I doubt it can be correct. If you want to offer simultaneous iterator-like operations to a collection, then the state of the iterator is bound to be outside said collection.
You can simply test using this:
int count1=0;
foreach(someType element in collection) count1++;
int count2=0;
foreach(someType element1 in collection) {
foreach(someType element2 in collection) {
count2++;
}
}
if (count2!=count1*count1) noGood();
|
|
|
|
|
DaveyM69 wrote: How about getting the enumerator
It seems you're still looking at it in the wrong way, when implemented properly there isn't just one enumerator to a collection, there are as many as you want (and that is why they need storage space outside the collection, hence a new action somewhere).
GetEnumerator returns an enumerator, not the enumerator.
|
|
|
|
|
This is what Reflector gives for List<T> GetEnumerator():
public Enumerator GetEnumerator()
{
return new Enumerator((List<T>) this);
}
Please notice the new keyword.
|
|
|
|
|
So when I call myFooCollection.GetEnumerator(); which in turn calls innerList.GetEnumerator(); where innerList is a List<T> I am actually getting a new enumertor anyway, and the same for myBarCollection.GetEnumerator(); , therefore there is no problem with:
IEnumerator<MyFoo> myFooEnumerator = myFooCollection.GetEnumerator();
while (myFooEnumerator.MoveNext())
yield return myFooEnumerator.Current;
IEnumerator<MyBar> myBarEnumerator = myBarCollection.GetEnumerator();
while (myBarEnumerator.MoveNext())
yield return myBarEnumerator.Current;
as a new enumerator for the collections is created everytime?
|
|
|
|
|
That seems correct. And the unit test I suggested earlier confirms it.
|
|
|
|
|
I know I'm late to the party here, but this question, and what's been exposed in the ensuing discussion, has "fit" with some aspects of use of classes I've been exploring.
1. I noted that in one of colleague PieBald's responses, he defined the Lists (alist, blist) that held collections of instances of classes A,B as static, and outside the scope of all three classes, which I found intriguing.
2. It seems to me that you could exploit the fact that each instantiation of Class A or B does invoke the constructor in class C:
private abstract class C
{
public static readonly List<A> alist = new List<A>();
public static readonly List<B> blist = new List<B>();
public static readonly List<C> clist = new List<C>();
public string Name { get; private set; }
public C(string Name)
{
this.Name = Name;
clist.Add(this);
if(this is A)
{
alist.Add(this as A);
}
else
{
blist.Add(this as B);
}
}
public override string ToString() { return (this.Name); }
} Using this implementation of Class C, you guarantee that all three lists are updated with each new instantiation of A or B.
Disclaimers-Dunno's:
1. don't know if this would play nice with .NET 2.0
2. thread safety ?
I've tested this code with the following:
A myA1 = new A("a1");
A myA2 = new A("a2");
B myB1 = new B("b1");
B myB2 = new B("b2");
foreach (var a in C.alist)
{
Console.WriteLine("This A's Name is : " + a.Name);
}
foreach (var b in C.blist)
{
Console.WriteLine("This B's Name is : " + b.Name);
}
foreach (var c in C.clist)
{
Console.WriteLine("This C is a Type: " + c.GetType() + " : Name = " + c.Name);
}
The results were as expected:
This A's Name is : a1
This A's Name is : a2
This B's Name is : b1
This B's Name is : b2
This C is a Type: TestImmutable.Form1+A : Name = a1
This C is a Type: TestImmutable.Form1+A : Name = a2
This C is a Type: TestImmutable.Form1+B : Name = b1
This C is a Type: TestImmutable.Form1+B : Name = b2 Be happy to have a critique of this approach.
thanks, Bill
When I consider the brief span of my life, swallowed up in the eternity before and after, the little space which I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which knows me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then. Blaise Pascal
|
|
|
|
|
hello guys... I have this DB in which I insert, update and delete data successfully. But problem comes when I try to add my own columns in Datagridview (Columns: Collection) and use the same code to get the data in it. But this does not show data in the columns already there and adds the new columns instead. Here is the code that I am using.
SqlConnection connection = new SqlConnection("Data Source=myServer; Initial Catalog=myDB; Integrated Security=True");
SqlDataAdapter adapter = new SqlDataAdapter("my SP name", connection);
DataTable dt = new DataTable();
try
{
connection.Open();
adapter.Fill(dt);
dg1.DataSource = dt;
}
catch (Exception ex)
{ connection.close(); MessageBox.Show(ex.Message);}
finally
{ connection.Close(); }
What can I do to add my own columns, but get the same data there in my own columns. thnx
|
|
|
|
|
You'll need to have everything you want in DataTable.
|
|
|
|
|
DataColumn myDataColumn;
myDataColumn = new DataColumn();
myDataColumn.DataType = System.Type.GetType("System.Int32");
myDataColumn.ColumnName = "id";
myDataColumn.ReadOnly = true;
myDataColumn.Unique = true;
myDataTable.Columns.Add(myDataColumn);
Source[^]
|
|
|
|
|
Thank you so much for your help. Now it is giving me new errors for something else and I dont understand. Does anyone know?
public static void Main()
{
stringinput,firstname,lastname;
double idium;
int password, choice;
string name;
Console.WriteLine("Enter your firstname:");
Console.WriteLine("Enter your ID Number:");
input = Console.ReadLine();
FirstName = Convert.ToString(input);
Console.WriteLine("Enter your lastname:");
input = Console.ReadLine();
LastName = Convert.ToString(input);
}
public static void checkout()
{
Console.Write("You are ready to check out.");
double[] payRate;
payRate = new double[4];
payRate[0] = 3.00;
payRate[1] = 4.15;
payRate[2] = 6.42;
payRate[3] = 7.95;
for(int x = 0; x < 4; ++x)
Console.WriteLine("Pay rate {0} is {1}", x, payRate[x].ToString("C"));
}
}
|
|
|
|
|
I will agree with Pete in your last posting - "This is fairly basic stuff". Perhaps you could look into a few online tutorials? That would probably help you to learn this better than asking several questions here.
Rather than trying to make a given block of code work, I would advise to learn the fundamentals instead...
|
|
|
|
|
Apart from the errors (tip: C# is case-sensitive), what's up with this?
Brian Reiber wrote: input = Console.ReadLine();
LastName = Convert.ToString(input);
It's already string, why convert a string to a string?
ILSpy confirms that the overload of Convert.ToString that takes a string argument just returns that string:
public static string ToString(string value)
{
return value;
}
|
|
|
|
|
Something else that you have failed to do is to show the actual error message that you receive. Don't expect others to be able to see what's happening on your PC when you try compiling this.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
What errors are you getting?
Brian Reiber wrote: stringinput
I suspect you mean string input
Brian Reiber wrote: input = Console.ReadLine();
FirstName = Convert.ToString(input);
Why not simply FirstName = Console.ReadLine(); ?
Brian Reiber wrote: Convert
I recommend never using Convert other than Convert.ChangeType
Brian Reiber wrote: {1} ... , payRate[x].ToString("C")
Try using {1:C} instead of the ToString.
|
|
|
|
|
Brian:
I am going to echo the recommendations of another post. As a new (and I really cannot refer to myself as a developer, yet) I researched online tutorials and books that would provide a foundation for C#, and VS 2010.
The following books have proven to be valuable resources:
1. Beginning C# Object Oriented Programming by Dan Clark (READ Chapter 5)
2. Visual C# 2010 Recipes by Jones and Freeman
3. HeadFirst C# by Stellman and Greene
4. Programming Language Pragmatics by Scott (buy it and put in on the bookshelf for a goal in understanding). It's beyond new developers, but it's a good feeling to go to the book and "get it" after study.
5. Herding Cats - A Primer for Programmers Who Lead Programmers by Rainwater (this book helps me understand those in the world of programming, as I come from the academic "world").
6. Online tutorials available from Lynda.com
My mentor (who has been programming since God was a child) says "Work on your errors for 2 hours, THEN ask for help".
My greatest hurdle has been in understanding the vocabulary that is used, and I finally had to stop obsessing... It is what it is.
Oh...Petzold's free online book (263 pages)was recommmended to me(Richard?), and is proving to be interesting, but I don't do well with books I cannot markup with pencil notations.
Two other books have been recommended, but they are on my Amazon wish list. Code Complete, and New Programmer's Survival Manual.
Looking at your code (I c/p'd into VS, and messed around with it), I was able to reduce the errors to 3, but then was stumped by my own ignorance...and I am not cheeky enough to make suggestions for changes. So your code helped me learn, so thank you.
Best of luck.
|
|
|
|
|
Deborah Palmer McCain wrote: I don't do well with books I cannot markup with pencil notations.
You can always print all or part of a PDF.
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
Yes, I read through part the book, and will be printing it so I can mark it. Truly a valuable resource, thank you again.
Deborah
|
|
|
|
|