Typed collection with Open Type Parameter - c#

I want to know why I am getting error if I write the below statement although I have mention at class level what is T
IList<T> targetObjectsCollection = new List<T>();
for (int counter = 0; counter < dataTransferObjects.Count; counter++)
{
targetObjectsCollection.Add(MappSharePointDAOToDTO(sharePointDaos[counter], dataTransferObjects[counter]));
}
and when I changed it to the following statement error has gone??
IList<IMapperMarker> targetObjectsCollection = new List<IMapperMarker>();
for (int counter = 0; counter < dataTransferObjects.Count; counter++)
{
targetObjectsCollection.Add(MappSharePointDAOToDTO(sharePointDaos[counter], dataTransferObjects[counter]));
}
can any body describe.

You do not seem to have defined T. It's a placeholder. It requires definition.
This code might work if it were used in a context where T had a definition. For instance,
private IList<T> AddDataTransferObjects(IList<T> dataTransferObjects)
: where T : IMapperMarker
{
IList<T> targetObjectsCollection = new List<T>();
for (int counter = 0; counter < dataTransferObjects.Count; counter++)
{
targetObjectsCollection.Add(MappSharePointDAOToDTO(sharePointDaos[counter], dataTransferObjects[counter]));
}
return targetObjectsCollection;
}
If you called that like this as follows:
IList<IMapperMarker> dtoList = Something();
var list = AddDataTransferObjects(dtoList);
In this case, the inner T would be bound to the type IMapperMarker.

Related

SynchronizedCollection InvalidOperationException/System.ArgumentException

I wrote some classes to test multithreading using SynchronizedCollection.
class MultithreadTesting
{
public readonly SynchronizedCollection<int> testlist = new SynchronizedCollection<int>();
public SynchronizedReadOnlyCollection<int> pubReadOnlyProperty
{
get
{
return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);
}
}
public void Test()
{
int numthreads = 20;
Thread[] threads = new Thread[numthreads];
List<Task> taskList = new List<Task>();
for (int i = 0; i < numthreads / 2; i++)
{
taskList.Add(Task.Factory.StartNew(() =>
{
for (int j = 0; j < 100000; j++)
{
testlist.Add(42);
}
}));
}
for (int i = numthreads / 2; i < numthreads; i++)
{
taskList.Add(Task.Factory.StartNew(() =>
{
var sum = 0;
foreach (int num in pubReadOnlyProperty)
{
sum += num;
}
}));
}
Task.WaitAll(taskList.ToArray());
testlist.Clear();
}
}
to run it I use
MultithreadTesting test = new MultithreadTesting();
while (true)
test.Test();
But the code throws me System.ArgumentException: 'Destination array was not long enough. Check destIndex and length, and the array's lower bounds.'
If I try to use testlist in foreach, I get
System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
However, MSDN tells us
SynchronizedReadOnlyCollection Class
Provides a thread-safe, read-only collection that contains objects of
a type specified by the generic parameter as elements.
The root cause of the error is that List<T> construction is not thread-safe.
Let's see what happens when constructing new SynchronizedReadOnlyCollection. Exception occurs in following line:
return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);
As exception StackTrace tells us, there is List<T>..ctor involved in construction process:
at System.Collections.Generic.SynchronizedCollection`1.CopyTo(T[] array, Int32 index)
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Collections.Generic.SynchronizedReadOnlyCollection`1..ctor(Object syncRoot, IEnumerable`1 list)
Following snippet from List<T> constructor shows where error happens. Code is copied from MS reference source, I cleaned unnecessary parts of code for easier reading. Please notice that between comments (1) and (2) there are other threads manipulating collection:
public List(IEnumerable<T> collection) {
ICollection<T> c = collection as ICollection<T>;
// (1) count is now current Count of collection
int count = c.Count;
// other threads can modify collection meanwhile
if (count == 0)
{
_items = _emptyArray;
}
else {
_items = new T[count];
// (2) SynchronizedCollection.CopyTo is called (which itself is thread-safe)
// Collection can still be modified between (1) and (2)
// No when _items.Count != c.Count -> Exception is raised.
c.CopyTo(_items, 0);
_size = count;
}
}
Solution
The problem can easily be fixed with locking testlist modification while constructing new SynchronizedReadOnlyCollection.
public SynchronizedReadOnlyCollection<int> pubReadOnlyProperty
{
get
{
lock (testlist.SyncRoot)
{
return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);
}
}
}

c# comparing list of IDs

I have a List<Keyword> where Keyword class is:
public string keyword;
public List<int> ids;
public int hidden;
public int live;
public bool worked;
Keyword has its own keyword, a set of 20 ids, live by default is set to 1 and hidden to 0.
I just need to iterate over the whole main List to invalidate those keywords whose number of same ids is greater than 6, so comparing every pair, if the second one has more than 6 ids repeated respect to the first one, hidden is set to 1 and live to 0.
The algorithm is very basic but it takes too long when the main list has many elements.
I'm trying to guess if there could be any method I could use to increase the speed.
The basic algorithm I use is:
foreach (Keyword main_keyword in lista_de_keywords_live)
{
if (main_keyword.worked) {
continue;
}
foreach (Keyword keyword_to_compare in lista_de_keywords_live)
{
if (keyword_to_compare.worked || keyword_to_compare.id == main_keyword.id) continue;
n_ids_same = 0;
foreach (int id in main_keyword.ids)
{
if (keyword_to_compare._lista_models.IndexOf(id) >= 0)
{
if (++n_ids_same >= 6) break;
}
}
if (n_ids_same >= 6)
{
keyword_to_compare.hidden = 1;
keyword_to_compare.live = 0;
keyword_to_compare.worked = true;
}
}
}
The code below is an example of how you would use a HashSet for your problem. However, I would not recommend using it in this scenario. On the other hand, the idea of sorting the ids to make the comparison faster still.
Run it in a Console Project to try it out.
Notice that once I'm done adding new ids to a keyword, I sort them. This makes the comparison faster later on.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace KeywordExample
{
public class Keyword
{
public List<int> ids;
public int hidden;
public int live;
public bool worked;
public Keyword()
{
ids = new List<int>();
hidden = 0;
live = 1;
worked = false;
}
public override string ToString()
{
StringBuilder s = new StringBuilder();
if (ids.Count > 0)
{
s.Append(ids[0]);
for (int i = 1; i < ids.Count; i++)
{
s.Append(',' + ids[i].ToString());
}
}
return s.ToString();
}
}
public class KeywordComparer : EqualityComparer<Keyword>
{
public override bool Equals(Keyword k1, Keyword k2)
{
int equals = 0;
int i = 0;
int j = 0;
//based on sorted ids
while (i < k1.ids.Count && j < k2.ids.Count)
{
if (k1.ids[i] < k2.ids[j])
{
i++;
}
else if (k1.ids[i] > k2.ids[j])
{
j++;
}
else
{
equals++;
i++;
j++;
}
}
return equals >= 6;
}
public override int GetHashCode(Keyword keyword)
{
return 0;//notice that using the same hash for all keywords gives you an O(n^2) time complexity though.
}
}
class Program
{
static void Main(string[] args)
{
List<Keyword> listOfKeywordsLive = new List<Keyword>();
//add some values
Random random = new Random();
int n = 10;
int sizeOfMaxId = 20;
for (int i = 0; i < n; i++)
{
var newKeyword = new Keyword();
for (int j = 0; j < 20; j++)
{
newKeyword.ids.Add(random.Next(sizeOfMaxId) + 1);
}
newKeyword.ids.Sort(); //sorting the ids
listOfKeywordsLive.Add(newKeyword);
}
//solution here
HashSet<Keyword> set = new HashSet<Keyword>(new KeywordComparer());
set.Add(listOfKeywordsLive[0]);
for (int i = 1; i < listOfKeywordsLive.Count; i++)
{
Keyword keywordToCompare = listOfKeywordsLive[i];
if (!set.Add(keywordToCompare))
{
keywordToCompare.hidden = 1;
keywordToCompare.live = 0;
keywordToCompare.worked = true;
}
}
//print all keywords to check
Console.WriteLine(set.Count + "/" + n + " inserted");
foreach (var keyword in set)
{
Console.WriteLine(keyword);
}
}
}
}
The obvious source of inefficiency is the way you calculate intersection of two lists (of ids). The algorithm is O(n^2). This is by the way problem that relational databases solve for every join and your approach would be called loop join. The main efficient strategies are hash join and merge join. For your scenario the latter approach may be better I guess, but you can also try HashSets if you like.
The second source of inefficiency is repeating everything twice. As (a join b) is equal to (b join a), you do not need two cycles over the whole List<Keyword>. Actually, you only need to loop over the non duplicate ones.
Using some code from here, you can write the algorithm like:
Parallel.ForEach(list, k => k.ids.Sort());
List<Keyword> result = new List<Keyword>();
foreach (var k in list)
{
if (result.Any(r => r.ids.IntersectSorted(k.ids, Comparer<int>.Default)
.Skip(5)
.Any()))
{
k.hidden = 1;
k.live = 0;
k.worked = true;
}
else
{
result.Add(k);
}
}
If you replace the linq with just the index manipulation approach (see the link above), it would be a tiny bit faster I guess.

Regarding local variable passing in Thread

I'm having a hard time in understanding the unexpected output for the following program:
class ThreadTest
{
static void Main()
{
for(int i = 0; i < 10; i++)
new Thread(() => Console.Write(i)).Start();
}
}
Queries:
Different code running in different thread have seperate stacks? If yes, than variables should preserve their values as int is a value type?
Each thread gets its own stack. The problem that you are facing has nothing to do with stack. The problem is the way it is generating code for your anonymous delegate. Use tool like refelector to understand the code that it is generating. The following will fix your problem:
static void Main()
{
for (int i = 0; i < 10; i++)
{
int capture = i;
new Thread(() => Console.Write(capture)).Start();
}
}
Under the hood
Whenever you use a variable from outer scope (in your case variable i) in anonymous delegate, the compiler generates a new class that wraps anonymous function along with the data that it uses from the outer scope. So in your case the generated class contains - one function and data member to capture the value of variable i. The class definition looks something like:
class SomeClass
{
public int i { get; set; }
public void Write()
{
Console.WriteLine(i);
}
}
The compiler re-writes your code as follows:
SomeClass someObj = new SomeClass();
for (int i = 0; i < 10; i++)
{
someObj.i = i;
new Thread(someObj.Write).Start();
}
and hence the problem - that you are facing. When you capture a variable, the compiler does the following:
for (int i = 0; i < 10; i++)
{
SomeClass someObj = new SomeClass();
someObj.i = i;
new Thread(someObj.Write).Start();
}
Note the difference in SomeClass instantiation. When you capture a variable, it creates as many instances as there are number of iterations. If you do not capture a variable, it tries to use the same instance for all iterations.
Hope, the above explanation will clarify your doubt.
Thanks
Yes, threads have their own stacks. But here you also have an issue with variable capture. Try changing the code to:
class ThreadTest
{
static void Main()
{
for(int i = 0; i < 10; i++)
{
int j = i;
new Thread(() => Console.Write(j)).Start();
}
}
}
Notice the change in output? Each thread is being started with a reference to the variable, not the value. When I insert the int j = i; line, we are breaking the variable capture. Your unexpected output has less to do with threading than it does closures.

mergesort - with an insignificant change throws SystemInvalidOperationException

A very strange thing occured in my program. Here is the simplified code.
class Program
{
static void Main(string[] args)
{
ArrayList numbers = new ArrayList();
numbers.Add(1);
numbers.Add(3);
numbers.Add(4);
numbers.Add(2);
var it = Sorts.MergeSort((ArrayList)numbers.Clone());
Sorts.PrintArray(it, "mergesort");
Console.WriteLine("DONE");
Console.ReadLine();
}
}
public static class Sorts
{
public static ArrayList BubbleSort(ArrayList numbers)
{
bool sorted = true;
for (int i = 0; i < numbers.Count; i++)
{
for (int j = 1; j < numbers.Count; j++)
{
if ((int)numbers[j - 1] > (int)numbers[j])
{
int tmp = (int)numbers[j - 1];
numbers[j - 1] = numbers[j];
numbers[j] = tmp;
sorted = false;
}
}
if (sorted)
{
return numbers;
}
}
return numbers;
}
public static ArrayList MergeSort(ArrayList numbers, int switchLimit = 3)
{
//if I use this if - everything works
if (numbers.Count <= 1)
{
// return numbers;
}
//the moment I use this condition - it throws SystemInvalidOperationException in function Merge in the line of a "for"-loop
if (numbers.Count <=switchLimit)
{
return Sorts.BubbleSort(numbers);
}
ArrayList ret = new ArrayList();
int middle = numbers.Count / 2;
ArrayList L = numbers.GetRange(0, middle);
ArrayList R = numbers.GetRange(middle, numbers.Count - middle);
L = MergeSort(L);
R = MergeSort(R);
return Merge(L, R);
}
private static ArrayList Merge(ArrayList L, ArrayList R)
{
ArrayList ret = new ArrayList();
int l = 0;
int r = 0;
for (int i = 0; i < L.Count + R.Count; i++)
{
if (l == L.Count)
{
ret.Add(R[r++]);
}
else if (r == R.Count)
{
ret.Add(L[l++]);
}
else if ((int)L[l] < (int)R[r])
{
ret.Add(L[l++]);
}
else
{
ret.Add(R[r++]);
}
}
return ret;
}
//---------------------------------------------------------------------------------
public static void PrintArray(ArrayList arr, string txt = "", int sleep = 0)
{
Console.WriteLine("{1}({0}): ", arr.Count, txt);
for (int i = 0; i < arr.Count; i++)
{
Console.WriteLine(arr[i].ToString().PadLeft(10));
}
Console.WriteLine();
System.Threading.Thread.Sleep(sleep);
}
}
There is a problem with my Sorts.MergeSort function.
When I use it normally (take a look at the first if-condition in a function - all works perfectly.
But the moment when I want it to switch to bubblesort with smaller input (the second if-condition in the function) it throws me an SystemInvalidOperationException. I have no idea where is the problem.
Do you see it?
Thanks. :)
Remark: bubblesort itself works - so there shouldn't be a problem in that sort...
The problem is with your use of GetRange:
This method does not create copies of the elements. The new ArrayList is only a view window into the source ArrayList. However, all subsequent changes to the source ArrayList must be done through this view window ArrayList. If changes are made directly to the source ArrayList, the view window ArrayList is invalidated and any operations on it will return an InvalidOperationException.
You're creating two views onto the original ArrayList and trying to work with both of them - but when one view modifies the underlying list, the other view is effectively invalidated.
If you change the code to create copies of the sublists - or if you work directly with the original list within specified bounds - then I believe it'll work fine.
(As noted in comments, I'd also strongly recommend that you use generic collections.)
Here's a short but complete program which demonstrates the problem you're running into:
using System;
using System.Collections;
class Program
{
static void Main()
{
ArrayList list = new ArrayList();
list.Add("a");
list.Add("b");
ArrayList view1 = list.GetRange(0, 1);
ArrayList view2 = list.GetRange(1, 1);
view1[0] = "c";
Console.WriteLine(view2[0]); // Throws an exception
}
}
on this line R = MergeSort(R); you alter the range of numbers represented by L. This invalidates L. Sorry I have to go so can't explain any further now.

C# Method which may execute any code in the loop

For example if i have to type something like that multiple time, is there any way to put this loop in the method with parameters like LoopMethod(Code lines, int count)
for (int i = 0; i <= 1000; i++)
{
code line 1;
code line 2;
...
code line N;
}
for (int i = 0; i <= 1000; i++)
{
code line 1;
code line 2;
...
code line N;
}
if result to have something like that.
LoopMethod{
code line 1,
code line 2,
...
code line N,
1000
}
Here's a variant:
public static LoopMethod(int iterations, Action<int> body)
{
for (int i = 0; i < iterations; i++)
body(i);
}
You'd call it like this:
LoopMethod(100, i =>
{
code line;
code line;
});
A more generic form would be to first create an extension method:
public static class Extension
{
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach(var currentItem in enumerable)
{
action(currentItem);
}
}
}
Then using that you can do the following:
Enumerable.Range(0, 1000).ForEach(i =>
{
Console.WriteLine(i);
});
Which would iterate from 0 to 999 (use 1001 as the second param for inclusive). The added benefit is that this then works on any enumerable type.
Well, you can do that with delegates rather easily:
public static void LoopMethod(Action loopCode, int count)
{
for (int i = 0; i < count ; ++i) loopCode();
}
public static void Main()
{
LoopMethod(() => {
code line 1;
code line 2;
code line 3;
}, 100);
}
You can alter that any way you like, even changing it to Action<int> which takes as a parameter the current loop counter. See #Gabe's answer for the Action<int> variant :)
Of course, I have to wonder why you want to reproduce such an obviously built-in construct like looping?
You could use lambda expression like this:
LoopMethod(() => {code line 1; code line 2;}, 100);
The method declaration would look something like
void LoopMethod (Action code, int count) {
for (int i = 0; i < count; i++) {
code();
}
}
There may be odd syntactical error there ( I haven't tested it), but the approach should work.

Categories