First off, if you are going to post code, then post
exactly the code that give you the problem - copy and paste it. The fragment you show isn't that: it won't compile because "thread" is not the same as "Thread" as far as C# is concerned. When you re-type it to end up with "something similar" which may or may not demonstrate the problem.
The problem is that things start to get a little hairy when you play with threads and anonymous delegates - because threads do not execute when you think they will, and if you start passing variable to delegates, you need to be sure what you are passing...
Try this instead (It's a cut down version of yours:
static void Main(string[] args)
{
List<string> l = new List<string>(250);
l.Add("a");
l.Add("b");
l.Add("c");
for (int i = 0; i < l.Count; i++)
{
string s = l[i];
Console.WriteLine("UI Thread: {0}:{1}", i, s);
Thread nt = new Thread(() => Console.WriteLine("Delegate : {0}:{1}", i, s));
nt.IsBackground = true;
nt.Start();
}
Console.ReadLine();
}
And look what you get:
UI Thread: 0:a
UI Thread: 1:b
UI Thread: 2:c
Delegate : 2:a
Delegate : 2:b
Delegate : 3:c
What? How did that happen?
Pretty simple: the integer is a Value type, which means that the variable itself is passed to the delegate rather than a reference to the variable. So it isn't the number it "contains" that is passed, it is the variable that holds the value. Which means that the value it holds is not examined until the thread itself runs - which may be at any time after the Thread.Start method has been called, depending on how many cores you have and whet else is going on in the system at that time.
In your code, that means that the value of "i" is not retrieved until after the loop ends sometimes, which means that it is outside the range of the list - and you get an exception.
Want to see how to "cure" this?
static void Main(string[] args)
{
List<string> l = new List<string>(250);
l.Add("a");
l.Add("b");
l.Add("c");
for (int i = 0; i < l.Count; i++)
{
string s = l[i];
Console.WriteLine("UI Thread: {0}:{1}", i, s);
int j = i;
Thread nt = new Thread(() => Console.WriteLine("Delegate : {0}:{1}:{2}",i, j, s));
nt.IsBackground = true;
nt.Start();
}
Console.ReadLine();
}
Now run that...:laugh:
"Sir,
A doubt:
below is just a pseudo code: a generic class, its constructor will be created only if the type parameter is an Enum.
class custom_dictionary<t>
{
static public custom_dictionary() {
if(!typeOf(T).IsEnum)
}
}
- I have used a static constructor here, what if i used an instance constructor?
- How do both vary from each other? and what about constraints to check if the type is Enum?
Thanks,
- Rahul"
First off, Is a static constructor going to work? Think about it: when is a static constructor executed, how often, and what happens if you have two instances of your class with different enums?
Second, there is a mechanism for doing that at compile time: Generic Constraints:
public class custom_dictionary<T> where T : Enum
{
}
What that does is says to the compiler: "This is a generic class, but I can only work with enums: if he tries to declare me with an int or a Textbox, tell him not to bother"
And it does:
custom_dictionary<StringSplitOptions> cd = new custom_dictionary<StringSplitOptions>();
Is fine, but
custom_dictionary<int> cd = new custom_dictionary<int>();
Will give you a "there is no boxing conversion" compiler error.
This is a lot, lot better than trying to do this at run time, because it moves the checking into the compiler - so your problem shows up much earlier: before you have coded for a couple of days and have to throw it all away the first time you test it!