Why am I getting a StackOverflow error in a long method? - c#

I have a small read-only database (based on data from services). The load time is critical so data can't be extracted from DB, XML and so on. I use the direct construction of data in the generated C# file:
void Load(){
var aa = new A[ 100500 ];
aa[0] = new A( ... );
...
aa[100499] = new A( ... );
AA = aa;
}
There are no recursion here, stackallocks and so on.
But I have got a StackOverflow error.
Looking in Disassembler window I found that JIT converts this code into:
var aa = new A[ 100500 ];
var a0 = new A( ... );
aa[0] = a0;
...
var a100499 = new A( ... );
aa[100499] = a100499;
So it create 100500 variables aXXXXX in stack:
-- aa[32] = new A( qwerty, asdf );
mov ecx,185C10h -- var a32 = new A
call 001730F4
mov dword ptr [ebp-4Ch],eax -- different for different rows
push dword ptr ds:[4403528h] -- a32.ctor( ... )
mov edx,dword ptr ds:[4403524h]
mov ecx,dword ptr [ebp-4Ch]
call 00790068
push dword ptr [ebp-4Ch] -- aa[32] = a32
mov ecx,dword ptr [ebp-3Ch]
mov edx,20h
call 71CCCD30
These changes doesn't help:
// 1. explicit variable
A a;
a = new A( ... ); // a32 = new A(...); a = a32;
aa[32] = a
// 2. limited visibility
{ aa[32] = new A( ... ); } // for each created object
This change helps but too ugly:
// Works in Release version only
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void f32( A[] aa )
=> aa[32] = new A( qwerty, asdf );
...
f32( aa ); -- inlined without a32
Is any elegant way to remove these stack devourers?
Thanks in advance.

Related

how to convert var to string in c# [duplicate]

I am trying to print out the contents of an array after invoking some methods which alter it, in Java I use:
System.out.print(Arrays.toString(alg.id));
how do I do this in c#?
You may try this:
foreach(var item in yourArray)
{
Console.WriteLine(item.ToString());
}
Also you may want to try something like this:
yourArray.ToList().ForEach(i => Console.WriteLine(i.ToString()));
EDIT: to get output in one line [based on your comment]:
Console.WriteLine("[{0}]", string.Join(", ", yourArray));
//output style: [8, 1, 8, 8, 4, 8, 6, 8, 8, 8]
EDIT(2019): As it is mentioned in other answers it is better to use Array.ForEach<T> method and there is no need to do the ToList step.
Array.ForEach(yourArray, Console.WriteLine);
There are many ways to do it, the other answers are good, here's an alternative:
Console.WriteLine(string.Join("\n", myArrayOfObjects));
The easiest one e.g. if you have a string array declared like this string[] myStringArray = new string[];
Console.WriteLine("Array : ");
Console.WriteLine("[{0}]", string.Join(", ", myStringArray));
I decided to test the speeds of the different methods posted here:
These are the four methods I used.
static void Print1(string[] toPrint)
{
foreach(string s in toPrint)
{
Console.Write(s);
}
}
static void Print2(string[] toPrint)
{
toPrint.ToList().ForEach(Console.Write);
}
static void Print3(string[] toPrint)
{
Console.WriteLine(string.Join("", toPrint));
}
static void Print4(string[] toPrint)
{
Array.ForEach(toPrint, Console.Write);
}
The results are as follows:
Strings per trial: 10000
Number of Trials: 100
Total Time Taken to complete: 00:01:20.5004836
Print1 Average: 484.37ms
Print2 Average: 246.29ms
Print3 Average: 70.57ms
Print4 Average: 233.81ms
So Print3 is the fastest, because it only has one call to the Console.WriteLine which seems to be the main bottleneck for the speed of printing out an array. Print4 is slightly faster than Print2 and Print1 is the slowest of them all.
I think that Print4 is probably the most versatile of the 4 I tested, even though Print3 is faster.
If I made any errors, feel free to let me know / fix them on your own!
EDIT: I'm adding the generated IL below
g__Print10_0://Print1
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldc.i4.0
IL_0003: stloc.1
IL_0004: br.s IL_0012
IL_0006: ldloc.0
IL_0007: ldloc.1
IL_0008: ldelem.ref
IL_0009: call System.Console.Write
IL_000E: ldloc.1
IL_000F: ldc.i4.1
IL_0010: add
IL_0011: stloc.1
IL_0012: ldloc.1
IL_0013: ldloc.0
IL_0014: ldlen
IL_0015: conv.i4
IL_0016: blt.s IL_0006
IL_0018: ret
g__Print20_1://Print2
IL_0000: ldarg.0
IL_0001: call System.Linq.Enumerable.ToList<String>
IL_0006: ldnull
IL_0007: ldftn System.Console.Write
IL_000D: newobj System.Action<System.String>..ctor
IL_0012: callvirt System.Collections.Generic.List<System.String>.ForEach
IL_0017: ret
g__Print30_2://Print3
IL_0000: ldstr ""
IL_0005: ldarg.0
IL_0006: call System.String.Join
IL_000B: call System.Console.WriteLine
IL_0010: ret
g__Print40_3://Print4
IL_0000: ldarg.0
IL_0001: ldnull
IL_0002: ldftn System.Console.Write
IL_0008: newobj System.Action<System.String>..ctor
IL_000D: call System.Array.ForEach<String>
IL_0012: ret
Another approach with the Array.ForEach<T> Method (T[], Action<T>) method of the Array class
Array.ForEach(myArray, Console.WriteLine);
That takes only one iteration compared to array.ToList().ForEach(Console.WriteLine) which takes two iterations and creates internally a second array for the List (double iteration runtime and double memory consumtion)
Starting from C# 6.0, when $ - string interpolation was introduced, there is one more way:
var array = new[] { "A", "B", "C" };
Console.WriteLine($"{string.Join(", ", array)}");
//output
A, B, C
Concatenation could be archived using the System.Linq, convert the string[] to char[] and print as a string:
var array = new[] { "A", "B", "C" };
Console.WriteLine($"{new String(array.SelectMany(_ => _).ToArray())}");
//output
ABC
In C# you can loop through the array printing each element. Note that System.Object defines a method ToString(). Any given type that derives from System.Object() can override that.
Returns a string that represents the current object.
http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx
By default the full type name of the object will be printed, though many built-in types override that default to print a more meaningful result. You can override ToString() in your own objects to provide meaningful output.
foreach (var item in myArray)
{
Console.WriteLine(item.ToString()); // Assumes a console application
}
If you had your own class Foo, you could override ToString() like:
public class Foo
{
public override string ToString()
{
return "This is a formatted specific for the class Foo.";
}
}
If you want to get cute, you could write an extension method that wrote an IEnumerable<object> sequence to the console. This will work with enumerables of any type, because IEnumerable<T> is covariant on T:
using System;
using System.Collections.Generic;
namespace Demo
{
internal static class Program
{
private static void Main(string[] args)
{
string[] array = new []{"One", "Two", "Three", "Four"};
array.Print();
Console.WriteLine();
object[] objArray = new object[] {"One", 2, 3.3, TimeSpan.FromDays(4), '5', 6.6f, 7.7m};
objArray.Print();
}
}
public static class MyEnumerableExt
{
public static void Print(this IEnumerable<object> #this)
{
foreach (var obj in #this)
Console.WriteLine(obj);
}
}
}
(I don't think you'd use this other than in test code.)
I upvoted the extension method answer by Matthew Watson, but if you're migrating/visiting coming from Python, you may find such a method useful:
class Utils
{
static void dump<T>(IEnumerable<T> list, string glue="\n")
{
Console.WriteLine(string.Join(glue, list.Select(x => x.ToString())));
}
}
-> this will print any collection using the separator provided. It's quite limited (nested collections?).
For a script (i.e. a C# console application which only contains Program.cs, and most things happen in Program.Main) - this may be just fine.
this is the easiest way that you could print the String by using array!!!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace arraypracticeforstring
{
class Program
{
static void Main(string[] args)
{
string[] arr = new string[3] { "Snehal", "Janki", "Thakkar" };
foreach (string item in arr)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
}
}
}
If it's an array of strings you can use Aggregate
var array = new string[] { "A", "B", "C", "D"};
Console.WriteLine(array.Aggregate((result, next) => $"{result}, {next}")); // A, B, C, D
that way you can reverses the order by changing the order of the parameters like so
Console.WriteLine(array.Aggregate((result, next) => $"{next}, {result}")); // D, C, B, A
You can use for loop
int[] random_numbers = {10, 30, 44, 21, 51, 21, 61, 24, 14}
int array_length = random_numbers.Length;
for (int i = 0; i < array_length; i++){
if(i == array_length - 1){
Console.Write($"{random_numbers[i]}\n");
} else{
Console.Write($"{random_numbers[i]}, ");
}
}
If you do not want to use the Array function.
public class GArray
{
int[] mainArray;
int index;
int i = 0;
public GArray()
{
index = 0;
mainArray = new int[4];
}
public void add(int addValue)
{
if (index == mainArray.Length)
{
int newSize = index * 2;
int[] temp = new int[newSize];
for (int i = 0; i < mainArray.Length; i++)
{
temp[i] = mainArray[i];
}
mainArray = temp;
}
mainArray[index] = addValue;
index++;
}
public void print()
{
for (int i = 0; i < index; i++)
{
Console.WriteLine(mainArray[i]);
}
}
}
class Program
{
static void Main(string[] args)
{
GArray myArray = new GArray();
myArray.add(1);
myArray.add(2);
myArray.add(3);
myArray.add(4);
myArray.add(5);
myArray.add(6);
myArray.print();
Console.ReadKey();
}
}

Delegate and method GetFunctionPointer

I am trying to figure out why one of these delegates is working differently under the hood. I have basically these kind of delegates:
private delegate void _SetSomething(bool value);
private delegate Something _Find(string value);
private delegate T _AddSomething<T>();
For each of these I have to know the memory address where they are pointing out, so I used GetFunctionPointer and I got three addresses, nothing special right now except for the fact I have to patch these addresses in memory, so I checked them in disassembly view and I saw for the first two methods the expected behaviours but not for the last:
var obj = new SomethingObj();
obj.SetSomething(true); // E8 XX XX XX XX calling exactly the first address got from the delegate
firstDel.DynamicInvoke(true); // starts calling from the fp value
var ret1 = obj.Find("something"); // E8 XX XX XX XX calling exactly the second address from the delegate
var ret2 = secondDel.DynamicInvoke("something"); // starts calling from the fp value
var ret3 = obj.AddSomething<SomeStuff>(); // E8 XX XX XX XX !!! Here the address does not match with the function pointer got from delegate
var ret4 = thirdDel.DynamicInvoke(null); // starts calling from the fp value...
I am running out of the options, I don't completly understand what is happening with the last delegate except for the fact that it is a little bit more complex of the others.
I don't really understand why is not the same address called by the instance method like the others two, anyone could help me out?
using System;
using System.Linq;
namespace Test
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new SomethingObj();
var firstDel = (_SetSomething) Delegate.CreateDelegate(typeof (_SetSomething), obj, "SetSomething");
var targetFind = typeof (SomethingObj).GetMethod("Find");
var secondDel = (_Find) Delegate.CreateDelegate(typeof (_Find), obj, targetFind, true);
var targetAdd = typeof (SomethingObj).GetMethods()
.First(m => m.Name == "AddSomething" && m.GetParameters().Length == 0)
.MakeGenericMethod(typeof (SomeStuff));
var thirdDel =
(_AddSomething<SomeStuff>) Delegate.CreateDelegate(typeof (_AddSomething<SomeStuff>), obj, targetAdd, true);
var firstAddress = firstDel.Method.MethodHandle.GetFunctionPointer();
var secondAddress = secondDel.Method.MethodHandle.GetFunctionPointer();
var thirdAddress = thirdDel.Method.MethodHandle.GetFunctionPointer();
obj.SetSomething(true); // E8 XX XX XX XX calling exactly the first address got from the delegate
firstDel.DynamicInvoke(true); // starts calling from the fp value
var ret1 = obj.Find("something"); // E8 XX XX XX XX calling exactly the second address from the delegate
var ret2 = secondDel.DynamicInvoke("something"); // starts calling from the fp value
var ret3 = obj.AddSomething<SomeStuff>(); // E8 XX XX XX XX !!! Here the address does not match with the function pointer got from delegate
var ret4 = thirdDel.DynamicInvoke(null); // starts calling from the fp value...
}
public class SomethingObj
{
public void SetSomething(bool value)
{
}
public SomeStuff AddSomething(Type type)
{
return new SomeStuff();
}
public T AddSomething<T>() where T : SomeStuff
{
return new SomeStuff() as T;
}
public SomeStuff AddSomething(string className)
{
return new SomeStuff();
}
public SomeStuff Find(string value)
{
return new SomeStuff();
}
}
public class SomeStuff
{
}
public class SomeStuffTest : SomeStuff
{
}
private delegate void _SetSomething(bool value);
private delegate SomeStuff _Find(string value);
private delegate T _AddSomething<T>();
}
}

Intersection between two geographic lines

I'm using the DotSpatial C# library and I'm trying to use the following code to try to find the intersection point between two lines (I know they do intersect)
var geoproj = DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984;
var d1 = new FeatureSet { Projection = geoproj };
//var c1 = new Coordinate(31.877484, 34.736723);
//var c2 = new Coordinate(31.879607, 34.732362);
var c1 = new Coordinate(0, -1);
var c2 = new Coordinate(0, 1);
var line1 = new LineString(new[] { c1, c2 });
d1.AddFeature(line1);
var d2 = new FeatureSet { Projection = geoproj };
//var c3 = new Coordinate(31.882391, 34.73352);
//var c4 = new Coordinate(31.875502, 34.734851);
var c3 = new Coordinate(-1, 0);
var c4 = new Coordinate(1, 0);
var line2 = new LineString(new[] { c3, c4 });
d2.AddFeature(line2);
var inters = d1.Intersection(d2, FieldJoinType.All, null);
var feats = inters.Features;
foreach (var feat in feats)
{
Console.WriteLine("{0}", feat.ToString());
}
The resulting feature set is always empty.
What am I doing wrong?
I also tried to swap the X and Y components for each coordinate (in case the first was assumed to be the longitude instead of the latitude)
Thanks!
EDIT: As per weston's comment below, I've changed the coordinates of the two lines to more obviously intersecting ones. The result is the same.
The intersection code you are using is basically a very limited shortcut. It is stuck with two conflicting ideas. The first idea is that featuresets all have the same feature type. That is, if you are working with a polygon featureset, all the features are polygons. The second idea is that the "intersection" of two lines is rarely a line. It is usually a point. So really that featureset intersecting code is designed to be used for intersecting polygons where the resulting shape is usually a polygon. It will also work for points where the results are always points. In your case, you probably want to find the union of the intersecting shapes, and throw out the shapes that do not intersect. You can accomplish this most easily by taking control of the features in a loop like the ones below. I have three examples, one that creates a point featureset from the intersections, and just assumes that all intersections will be points, one that keeps the original d1 feature if it intersects with a d2 feature, and another that unions all the intersecting d2 features with each d1 feature. This has the potential of creating some duplication of d2 content if a d2 feature intersects with more than one d1 feature. In any of these cases, it may not be clear what to do with the attributes, since the intersection could officially possess attributes that belong to multiple d2 shapes, not just one, so that would also have to be handled in a custom way that is meaningful for your specific application.
var geoproj = DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984;
var d1 = new FeatureSet { Projection = geoproj };
//var c1 = new Coordinate(31.877484, 34.736723);
//var c2 = new Coordinate(31.879607, 34.732362);
var c1 = new Coordinate(0, -1);
var c2 = new Coordinate(0, 1);
var line1 = new LineString(new[] { c1, c2 });
d1.AddFeature(line1);
var d2 = new FeatureSet { Projection = geoproj };
//var c3 = new Coordinate(31.882391, 34.73352);
//var c4 = new Coordinate(31.875502, 34.734851);
var c3 = new Coordinate(-1, 0);
var c4 = new Coordinate(1, 0);
var line2 = new LineString(new[] { c3, c4 });
d2.AddFeature(line2);
// To create a Point featureset with the intersections
var result = new FeatureSet(FeatureType.Point) { Projection = geoproj };
foreach (IFeature feature in d1.Features)
{
foreach (IFeature other in d2.Features)
{
if (feature.Intersects(other))
{
result.AddFeature(feature.Intersection(other));
}
}
}
// To keep only d1 lines that intersect with d2
result = new FeatureSet { Projection = geoproj };
foreach(IFeature feature in d1.Features){
foreach(IFeature other in d2.Features){
if(feature.Intersects(other)){
result.AddFeature(feature);
}
}
}
// Alternately to combine the intersecting lines into a cross
result = new FeatureSet { Projection = geoproj };
foreach (IFeature feature in d1.Features)
{
IFeature union = feature;
Boolean keep = false;
foreach (IFeature other in d2.Features)
{
if (feature.Intersects(other))
{
union = union.Union(other);
keep = true;
}
}
if (keep)
{
result.AddFeature(union);
}
}

printing all contents of array in C#

I am trying to print out the contents of an array after invoking some methods which alter it, in Java I use:
System.out.print(Arrays.toString(alg.id));
how do I do this in c#?
You may try this:
foreach(var item in yourArray)
{
Console.WriteLine(item.ToString());
}
Also you may want to try something like this:
yourArray.ToList().ForEach(i => Console.WriteLine(i.ToString()));
EDIT: to get output in one line [based on your comment]:
Console.WriteLine("[{0}]", string.Join(", ", yourArray));
//output style: [8, 1, 8, 8, 4, 8, 6, 8, 8, 8]
EDIT(2019): As it is mentioned in other answers it is better to use Array.ForEach<T> method and there is no need to do the ToList step.
Array.ForEach(yourArray, Console.WriteLine);
There are many ways to do it, the other answers are good, here's an alternative:
Console.WriteLine(string.Join("\n", myArrayOfObjects));
The easiest one e.g. if you have a string array declared like this string[] myStringArray = new string[];
Console.WriteLine("Array : ");
Console.WriteLine("[{0}]", string.Join(", ", myStringArray));
I decided to test the speeds of the different methods posted here:
These are the four methods I used.
static void Print1(string[] toPrint)
{
foreach(string s in toPrint)
{
Console.Write(s);
}
}
static void Print2(string[] toPrint)
{
toPrint.ToList().ForEach(Console.Write);
}
static void Print3(string[] toPrint)
{
Console.WriteLine(string.Join("", toPrint));
}
static void Print4(string[] toPrint)
{
Array.ForEach(toPrint, Console.Write);
}
The results are as follows:
Strings per trial: 10000
Number of Trials: 100
Total Time Taken to complete: 00:01:20.5004836
Print1 Average: 484.37ms
Print2 Average: 246.29ms
Print3 Average: 70.57ms
Print4 Average: 233.81ms
So Print3 is the fastest, because it only has one call to the Console.WriteLine which seems to be the main bottleneck for the speed of printing out an array. Print4 is slightly faster than Print2 and Print1 is the slowest of them all.
I think that Print4 is probably the most versatile of the 4 I tested, even though Print3 is faster.
If I made any errors, feel free to let me know / fix them on your own!
EDIT: I'm adding the generated IL below
g__Print10_0://Print1
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldc.i4.0
IL_0003: stloc.1
IL_0004: br.s IL_0012
IL_0006: ldloc.0
IL_0007: ldloc.1
IL_0008: ldelem.ref
IL_0009: call System.Console.Write
IL_000E: ldloc.1
IL_000F: ldc.i4.1
IL_0010: add
IL_0011: stloc.1
IL_0012: ldloc.1
IL_0013: ldloc.0
IL_0014: ldlen
IL_0015: conv.i4
IL_0016: blt.s IL_0006
IL_0018: ret
g__Print20_1://Print2
IL_0000: ldarg.0
IL_0001: call System.Linq.Enumerable.ToList<String>
IL_0006: ldnull
IL_0007: ldftn System.Console.Write
IL_000D: newobj System.Action<System.String>..ctor
IL_0012: callvirt System.Collections.Generic.List<System.String>.ForEach
IL_0017: ret
g__Print30_2://Print3
IL_0000: ldstr ""
IL_0005: ldarg.0
IL_0006: call System.String.Join
IL_000B: call System.Console.WriteLine
IL_0010: ret
g__Print40_3://Print4
IL_0000: ldarg.0
IL_0001: ldnull
IL_0002: ldftn System.Console.Write
IL_0008: newobj System.Action<System.String>..ctor
IL_000D: call System.Array.ForEach<String>
IL_0012: ret
Another approach with the Array.ForEach<T> Method (T[], Action<T>) method of the Array class
Array.ForEach(myArray, Console.WriteLine);
That takes only one iteration compared to array.ToList().ForEach(Console.WriteLine) which takes two iterations and creates internally a second array for the List (double iteration runtime and double memory consumtion)
Starting from C# 6.0, when $ - string interpolation was introduced, there is one more way:
var array = new[] { "A", "B", "C" };
Console.WriteLine($"{string.Join(", ", array)}");
//output
A, B, C
Concatenation could be archived using the System.Linq, convert the string[] to char[] and print as a string:
var array = new[] { "A", "B", "C" };
Console.WriteLine($"{new String(array.SelectMany(_ => _).ToArray())}");
//output
ABC
In C# you can loop through the array printing each element. Note that System.Object defines a method ToString(). Any given type that derives from System.Object() can override that.
Returns a string that represents the current object.
http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx
By default the full type name of the object will be printed, though many built-in types override that default to print a more meaningful result. You can override ToString() in your own objects to provide meaningful output.
foreach (var item in myArray)
{
Console.WriteLine(item.ToString()); // Assumes a console application
}
If you had your own class Foo, you could override ToString() like:
public class Foo
{
public override string ToString()
{
return "This is a formatted specific for the class Foo.";
}
}
If you want to get cute, you could write an extension method that wrote an IEnumerable<object> sequence to the console. This will work with enumerables of any type, because IEnumerable<T> is covariant on T:
using System;
using System.Collections.Generic;
namespace Demo
{
internal static class Program
{
private static void Main(string[] args)
{
string[] array = new []{"One", "Two", "Three", "Four"};
array.Print();
Console.WriteLine();
object[] objArray = new object[] {"One", 2, 3.3, TimeSpan.FromDays(4), '5', 6.6f, 7.7m};
objArray.Print();
}
}
public static class MyEnumerableExt
{
public static void Print(this IEnumerable<object> #this)
{
foreach (var obj in #this)
Console.WriteLine(obj);
}
}
}
(I don't think you'd use this other than in test code.)
I upvoted the extension method answer by Matthew Watson, but if you're migrating/visiting coming from Python, you may find such a method useful:
class Utils
{
static void dump<T>(IEnumerable<T> list, string glue="\n")
{
Console.WriteLine(string.Join(glue, list.Select(x => x.ToString())));
}
}
-> this will print any collection using the separator provided. It's quite limited (nested collections?).
For a script (i.e. a C# console application which only contains Program.cs, and most things happen in Program.Main) - this may be just fine.
this is the easiest way that you could print the String by using array!!!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace arraypracticeforstring
{
class Program
{
static void Main(string[] args)
{
string[] arr = new string[3] { "Snehal", "Janki", "Thakkar" };
foreach (string item in arr)
{
Console.WriteLine(item.ToString());
}
Console.ReadLine();
}
}
}
If it's an array of strings you can use Aggregate
var array = new string[] { "A", "B", "C", "D"};
Console.WriteLine(array.Aggregate((result, next) => $"{result}, {next}")); // A, B, C, D
that way you can reverses the order by changing the order of the parameters like so
Console.WriteLine(array.Aggregate((result, next) => $"{next}, {result}")); // D, C, B, A
You can use for loop
int[] random_numbers = {10, 30, 44, 21, 51, 21, 61, 24, 14}
int array_length = random_numbers.Length;
for (int i = 0; i < array_length; i++){
if(i == array_length - 1){
Console.Write($"{random_numbers[i]}\n");
} else{
Console.Write($"{random_numbers[i]}, ");
}
}
If you do not want to use the Array function.
public class GArray
{
int[] mainArray;
int index;
int i = 0;
public GArray()
{
index = 0;
mainArray = new int[4];
}
public void add(int addValue)
{
if (index == mainArray.Length)
{
int newSize = index * 2;
int[] temp = new int[newSize];
for (int i = 0; i < mainArray.Length; i++)
{
temp[i] = mainArray[i];
}
mainArray = temp;
}
mainArray[index] = addValue;
index++;
}
public void print()
{
for (int i = 0; i < index; i++)
{
Console.WriteLine(mainArray[i]);
}
}
}
class Program
{
static void Main(string[] args)
{
GArray myArray = new GArray();
myArray.add(1);
myArray.add(2);
myArray.add(3);
myArray.add(4);
myArray.add(5);
myArray.add(6);
myArray.print();
Console.ReadKey();
}
}

C# - Formatting .txt Document Problem

Here is the text file that I am loading in:
ORIGINAL FILE
10 BARE PCB
20 T C40
B C5, C45, C48
30 B C25
40 B C17, C18
50 B C15
60 T C20, C23,
B C6, C7, C8, C9, C10, C11, C12,
C31, C32, C33, C34, C35, C36,
C37, C38, C39
70 T C16, C21, C22, C24, C41, C42
B C3, C19, C43, C44, C47
80 T C13, C14
B C1, C2
90 B C26, C27, C28, C29, C30
100 T R65
110 T R35
120 T R34
130 T R33
140 T R21, R22, R29, R30
150 B R28, R31, R32, R37
160 T R17, R19, R26, R47, R50, R51,
R53, R57, R58, R59
B R18, R25, R42, R48, R49, R52,
R54, R55, R56, R60
170 T R23
B R10, R43
180 T R8, R9
190 T R13, R14, R15, R61, R62, R63,
R64
200 T R27, R38, R39, R40, R41
B R2, R3, R11, R44, R45, R46
210 B R1
220 T C4
230 T D1
240 T U1
250 B U10
270 B U6
280 B U5
290 B U4
300 T U2
310 B U7
320 B U8
330 T U9
340 B L2, L3
350 B L8, L9
360 B L1, L4, L5, L6, L7, L10
370 B J1, J2
380 B J3
390 B X1
400 T X2
410 B J4
420 B J5
422 B U3
2000 T TRACKING LABEL
423 ADHESIVE
424 ACCELERATOR
425 ADHESIVE
And this is what I have the file being formatted to:
FORMATTED FILE
0010 BARE PCB
0020 C40
0020A C5, C45, C48
0030A C25
0040A C17, C18
0050A C15
0060 C20, C23,
0060A C6, C7, C8, C9, C10, C11, C12,C31, C32, C33, C34, C35, C36,C37, C38, C39
0070 C16, C21, C22, C24, C41, C42
0070A C3, C19, C43, C44, C47
0080 C13, C14
0080A C1, C2
0090A C26, C27, C28, C29, C30
0100 R65
0110 R35
0120 R34
0130 R33
0140 R21, R22, R29, R30
0150A R28, R31, R32, R37
0160 R17, R19, R26, R47, R50, R51,R53, R57, R58, R59
0160A R18, R25, R42, R48, R49, R52,R54, R55, R56, R60
0170 R23
0170A R10, R43
0180 R8, R9
0190 R13, R14, R15, R61, R62, R63,R64
0200 R27, R38, R39, R40, R41
0200A R2, R3, R11, R44, R45, R46
0210A R1
0220 C4
0230 D1
0240 U1
0250A U10
0270A U6
0280A U5
0290A U4
0300 U2
0310A U7
0320A U8
0330 U9
0340A L2, L3
0350A L8, L9
0360A L1, L4, L5, L6, L7, L10
0370A J1, J2
0380A J3
0390A X1
0400 X2
0410A J4
0420A J5
0422A U3
2000 TRACKING LABEL
0423 ADHESIVE
0424 ACCELERATOR
0425 ADHESIVE
HOWEVER
If you look closely in the formatted file there is a few spots where there is no space after one of the commas (C12,C31 & C36,C37 & R51,R53 & R52,R54 & R63,R64). I would like there to be a space in between there..
CODE
private void openRefsFormatHelper()
{
try
{
// Resets the formatted refs text.
formattedRefsTextRichTextBox.ResetText();
// Reads the lines in the file to format.
var reader = File.OpenText(openRefs.FileName);
// Creates a list for the lines to be stored in.
var list = new List<string>();
// Adds each line in the file to the list.
while (true)
{
var line = reader.ReadLine();
if (line == null)
break;
list.Add(line);
}
// Handles all of the requirements for the reference text.
list = fourDigitRequirement(list);
list = concatRequirement(list);
list = startsWithBRequirement(list);
list = elementIsBRequirement(list);
list = removeTRequirement(list);
// Prints the formatted refs to the richtextbox.
foreach (var line in list)
formattedRefsTextRichTextBox.AppendText(line + "\n");
}
// Catches an exception if the file could not be formatted.
catch (Exception)
{
MessageBox.Show("There was a problem formatting the 'Refs File'.", "Refs File Format Error",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
static List<string> elementIsBRequirement(List<string> list)
{
// Creates a new list to return with new format.
var result = new List<string>();
// Checks each line in the list.
foreach (var line in list)
{
// Splits each line into 'parts'
var parts = line.Split(' ');
// Checks if the second 'part' array is "B"
if (parts[1].Equals("B"))
{
// If it is "B", replace with "A" and add to the new list "result"
parts[0] += "A";
parts[1] = string.Empty;
result.Add(string.Join(" ", parts));
}
// Otherwise keep the line how it is.
else
result.Add(line);
}
// Returns the new list so it can be formatted further.
return result;
}
static List<string> startsWithBRequirement(List<string> list)
{
// Creates a new list to return with new format.
var result = new List<string>();
var i = 0;
// Checks if the line begins with "B"
foreach (var line in list)
{
// Splits each line into 'parts'
var parts = line.Split(' ');
// Checks if the first 'part' array is "B"
if (parts[0].Equals("B"))
{
// If it is "B", copy the previous line down and add "A" where "B" was at
// and add to the new list "result".
parts[0] = string.Empty;
result.Add(list[i - 1].Split(' ')[0] + "A" + string.Join(" ", parts));
}
// Otherwise keep the line how it is.
else
result.Add(line);
i++;
}
// Returns the new list so it can be formatted further.
return result;
}
static List<string> concatRequirement(List<string> list)
{
// Creates a new list to return with new format.
var result = new List<string>();
// Checks each line in the list.
foreach (var line in list)
{
// Splits each line into 'parts'
var parts = line.Split(' ');
int test;
// Concats everything together
if (int.TryParse(parts[0], out test) || parts[0].Equals("B"))
result.Add(line);
// Otherwise result - 1
else
result[result.Count - 1] += line;
}
// Returns the new list so it can be formatted further.
return result;
}
static List<string> removeTRequirement(List<string> list)
{
// Creates a new list to return with new format.
var result = new List<string>();
// Checks each line in the list.
foreach (var line in list)
{
// Splits each line into 'parts'
var parts = line.Split(' ');
// Checks if the second 'part' array is "T", if it is, remove "T"
if (parts[1].Equals("T"))
parts[1] = string.Empty;
// Add the new string to the result.
result.Add(string.Join(" ", parts).Replace(" ", " "));
}
// Returns the new list so it can be formatted further.
return result;
}
static List<string> fourDigitRequirement(List<string> list)
{
// Creates a new list to return with new format.
var result = new List<string>();
// Checks each line in the list.
foreach (var line in list)
{
// Splits each line into 'parts'
var parts = line.Split(' ');
int test;
// Checks if the array[0] (digits) is the proper length.
if (int.TryParse(parts[0], out test))
{
// If it is not a length of 4 digits, add "O" to the front until it is.
parts[0] = parts[0].PadLeft(4, '0');
// Add the new string to the result list.
result.Add(string.Join(" ", parts));
}
// Otherwise keep the line how it is.
else
result.Add(line);
}
// Returns the new list so it can be formatted further.
return result;
}
QUESTION:
- How do I get that space in there?
In concatRequirement, you can change:
result[result.Count - 1] += line;
to
result[result.Count - 1] += " " + line;
Without desk-checking the whole thing, I notice that the problem entries are where the value is at the end of the line.
Try appending a space to the line before you split it. Maybe.

Categories