How to manipulate structure (array inside)? - c#

This is the structure:
public struct ProfilePoint
{
public double x;
public double z;
byte intensity;
}
It is used inside a callback function (I deleted most of it so it won't make sense, there is a for loop that cycle through every points (arrayIndex) that were scanned on a surface and process them. The result is stored inside profileBuffer):
public static void onData(KObject data)
{
if (points[arrayIndex].x != -32768)
{
profileBuffer[arrayIndex].x = 34334;
profileBuffer[arrayIndex].z = 34343;
validPointCount++;
}
else
{
profileBuffer[arrayIndex].x = 32768;
profileBuffer[arrayIndex].z = 32768;
}
}
}
I would like to process the data inside profileBuffer (both array, x & z).
So far I was "able" to create a function that get one value from profileBuffer with no error from visual studio:
public static int ProcessProfile(double dataProfile)
{
int test=1;
return test;
}
Putting this line:
ProcessProfile(profileBuffer[1].x);
Into onData() result in no error but that's just one value. Ideally, I would like to have the whole array. What confuse me is that every value stored inside profileBuffer are double (forget intensity). But stored in array. Yet I can't import the data like ProcessProfile(profileBuffer.x); I have to specify an index... Is it possible to manipulate a vector (line) of data? That would be ideal for me.
Sorry for the poor explanation / long post... I am quite newb.

you need
public static int ProcessProfile(ProfilePoint []points)
{
var x = points[4].x;
.....
}
and do
ProcessProfile(profileBuffer);

Related

Should I use Int32[,] or System.Drawing.Point when all I want is the x,y coordinates?

I am building an app that lets me control my Android devices from my PC. It's running great so now I want to start cleaning up my code for release. I'm trying to clean up solution references that I don't need so I took a look at the using System.Drawing; that I have for implementing the Point class. The thing is, I don't really need it if I switch to using a two-dimensional Int32 array.
So I could have: new Int32[,] {{200, 300}}; instead of new Point(200, 300); and get rid of the System.Drawing namespace altogether. The question is: does it really matter? Am I realistically introducing bloat in my app by keeping the System.Drawing namespace? Is Int32[,] meaningfully more lightweight?
Or, should I not use either and just keep track of the x,y coordinates in individual Int32 variables?
EDIT: I got rid of the original idea I wrote: Int32[200, 300] and replaced it with new Int32[,] {{200, 300}}; because as #Martin Mulder pointed out Int32[200, 300] "creates a two-dimensional array with 60000 integers, all of them are 0."
EDIT2: So I'm dumb. First of all I was trying to fancify too much by using the multi-dimensional array. Utter, overboard silliness. Secondly, I took the advice to use a struct and it all worked flawlessly, so thank you to the first four answers; every one of them was correct. But, after all that, I couldn't end up removing the System.Drawing reference because I was working on a WinForms app and the System.Drawing is being used all over in the designer of the app! I suppose I could further refactor it but I got the size down to 13KB so it's good enough. Thank you all!
Just create your own:
public struct Point : IEquatable<Point>
{
private int _x;
private int _y;
public int X
{
get { return _x; }
set { _x = value; }
}
public int Y
{
get { return _y; }
set { _y = value; }
}
public Point(int x, int y)
{
_x = x;
_y = y;
}
public bool Equals(Point other)
{
return X == other.X && Y == other.Y;
}
public override bool Equals(object other)
{
return other is Point && Equals((Point)other);
}
public int GetHashCode()
{
return unchecked(X * 1021 + Y);
}
}
Better yet, make it immutable (make the fields readonly and remove the setters), though if you'd depended on the mutability of the two options you consider in your question then that'll require more of a change to how you do things. But really, immutability is the way to go here.
You are suggesting very ill advised:.
new Point(200, 300) creates a new point with two integers: The X and Y property with values 200 and 300.
new Int32[200,300] creates a two-dimensional array with 60000 integers, all of them are 0.
(After your edit) new Int32[,] {{200, 300}} also creates a two-dimensional array, this time with 2 integers. To retrieve the first value (200), you can access it like this: array[0,0] and the second value (300) like array[0,1]. The second dimension is not required or needed or desired.
If you want to get rid of the reference to the library there are a few other suggestions:
new Int32[] {200, 300} creates an one-dimensional array of two integers with values 200 and 300. You can access them with array[0] and array[1].
As Ron Beyer suggested, you could use Tuple<int, int>.
Create your own Point-struct (pointed out by Jon Hanna). It makes your applicatie a bit larger, but you prevent the reference and you prevent the library System.Drawing is loaded into memory.
If I wanted to remove that reference, I would go for the last option since it is more clear to what I am doing (a Point is more readable than an Int32-array or Tuple). Solution 2 and 3 are slightly faster that solution 1.
Nothing gets "embedded" in your application by just referencing a library. However, if the Point class really is all you need, you could just remove the reference and implement you own Point struct. That may be more intuitive to read instead of an int array.
Int32[,] is something different by the way. It's a two-dimensional array, not a pair of two int values. You'll be making things worse by using that.
You could use Tuple<int, int>, but I'd go for creating your own structure.
As some people have suggested implementations here. So just wrap your two integers, I'd just use this:
public class MyPoint
{
public int X;
public int Y;
}
Add all other features only if needed.
As #Glorin Oakenfoot said, you should implement your own Point class. Here's an example:
public class MyPoint // Give it a unique name to avoid collisions
{
public int X { get; set; }
public int Y { get; set; }
public MyPoint() {} // Default constructor allows you to use object initialization.
public MyPoint(int x, int y) { X = x, Y = y }
}

Having trouble with moving information

I seem to of hit a bit of a snag in a program I am trying to make for school. I am suppose to make a new class to receive data and get a total to send to a new screen. Well I did the same thing we did in class, but the difference is that that was from a text box and there is no text box for the data I need to move this time, so the way I tried gave me an error. Here is what I got so far:
public StudentSelection()
{
InitializeComponent();
}
public decimal firstCounter;
public decimal secondCounter;
public decimal finalCounter;
struct StudentScores
{
public string StuId;
public decimal TestOne;
public decimal TestTwo;
public decimal Final;
}
StudentScores[] allStudentScores = new StudentScores[10];
// class level array to hold 10 products - read in from a file
private void StudentSelection_Load(object sender, EventArgs e)
{
// read products file into products structure array
try
{
// ALWAYS initialize a structure array before using the array
// before adding, changing, etc.
for (int x = 0; x < 10; x++)
{
allStudentScores[x].StuId = "";
allStudentScores[x].TestOne = 0;
allStudentScores[x].TestTwo = 0;
allStudentScores[x].Final = 0;
}
int arrayIndex = 0; // needed for incrementing index value of the array
// when reading file into array
// now read file into the array after initialization
StreamReader inputFile;
string lineofdata; // used to hold each line of data read in from the file
string[] ProductStringArray = new string[4]; // 6 element string array to hold
// each "field" read from every line in file
inputFile = File.OpenText("StudentScores.txt"); // open for reading
while (!inputFile.EndOfStream) //keep reading until end of file
{
lineofdata = inputFile.ReadLine(); // ReadLine() reads an entire row of data from file
ProductStringArray = lineofdata.Split(','); //each field is separated by ';'
allStudentScores[arrayIndex].StuId = ProductStringArray[0]; // add first element of array to first column of allProducts
allStudentScores[arrayIndex].TestOne = decimal.Parse(ProductStringArray[1]);
firstCounter += allStudentScores[arrayIndex].TestOne;
allStudentScores[arrayIndex].TestTwo = decimal.Parse(ProductStringArray[2]);
secondCounter += allStudentScores[arrayIndex].TestTwo;
allStudentScores[arrayIndex].Final = decimal.Parse(ProductStringArray[3]);
finalCounter += allStudentScores[arrayIndex].Final;
StudentListView.Items.Add(ProductStringArray[0]);
arrayIndex++; // increment so NEXT row is updated with next read
}
//close the file
inputFile.Close();
}
catch (Exception anError)
{
MessageBox.Show(anError.Message);
}
}
private void NextButton_Click(object sender, EventArgs e)
{
decimal firstResult, secondResult, finalResult, stuOne, stuTwo, stuThree;
string stuName;
// call the method in our datatier class
decimal.TryParse(firstCounter, out firstResult);
decimal.TryParse(secondCounter, out secondResult);
decimal.TryParse(finalCounter, out finalResult);
DataTier.AddOurNumbers(firstResult, secondResult, finalResult);
DataTier.StudentData(stuName, stuOne, stuTwo, stuThree);
// now hide this window and display a third window with the total
this.Hide();
// display third window
ScoreScreen aScoreScreen = new ScoreScreen();
aScoreScreen.Show();
}
}
and my new class
class DataTier
{
// public static variable available to all windows
public static decimal firstTotal, secondTotal, finalTotal, stuTestOne, stuTestTwo, stuTestThree;
// static is not associated with any object
public static string stuIDCode;
// create a public method to access from all windows
public static void AddOurNumbers(decimal NumOne, decimal NumTwo, decimal numThree)
{
// devide to get an average
firstTotal = NumOne / 10;
secondTotal = NumTwo / 10;
finalTotal = numThree / 10;
}
public static void StudentData(string name, decimal testOne, decimal testTwo, decimal testThree)
{
stuIDCode = name;
stuTestOne = testOne;
stuTestTwo = testTwo;
stuTestThree = testThree;
}
}
The error is at the three decimal.TryParse parts and I have no clue why it is not working except the error says "cannot convert from decimal to string". Any help will be appreciated.
Change it from:
decimal.TryParse(firstCounter, out firstResult);
decimal.TryParse(secondCounter, out secondResult);
decimal.TryParse(finalCounter, out finalResult);
DataTier.AddOurNumbers(firstResult, secondResult, finalResult);
To:
DataTier.AddOurNumbers(firstCounter, secondCounter, finalCounter);
The problem is that you're trying to call decimal.TryParse(string s, out decimal result) as decimal.TryParse(decimal s, out decimal result).
Your input is already decimal and doesn't require any conversion.
As a side note is that the code
decimal.TryParse(someString, out someOutputDecimal);
without a proper if statement around it will fail silently (it doesn't inform anything about the failure). In fact the output value is set to 0, and it acts as if no faulty input was received. If the input should always be valid, you should use decimal.Parse(someString) instead. However in some cases defaulting to 0 if the input is invalid, can be the desired behavior.
The decimal.TryParse() method takes a string as its first argument and attempts to convert it to a decimal value. In your case, the variables you are passing to TryParse() are already decimal variables and there is no need to parse them. If you want to just copy class variables to local variables, all you need to do is this:
firstResult = firstCounter;
secondResult = secondCounter;
finalResult = finalCounter;
Or in this particular case, you can just pass the class variables directly into AddOurNumbers:
DataTier.AddOurNumbers(firstCounter, secondCounter, finalCounter);
One thing to note here is that value types, such as decimals and other primitives in C# get copied any time you assign them from one value to another, or pass them into a method. This means that even if the value of firstCounter, secondCounter, or thirdCounter changes after calling DataTier.AddOurNumbers(), the values that your data tier has already recieved will not change.

how to reference a value in a C# array

i have the following array :
int[] myArray = {21,21,364,658,87};
and a reference to the second element like so:
int rr = myArray[1];
i want something like :
rr = 500
Console.writeLine(myArray[1]);// ---> should print 500 !
i hope you guys got my idea , i can do this easily in python like the example above.
so
how to do this in C#
my solution would probably be create property with arr[1] as its backing property
something like:
public int rr
{
set{ arr[1] = value;}
get{ return arr[1];}
}
and than rr=500; will be the same as arr[1]=500;
You could use something like this:
public static class ArrayExtensions
{
public static Action<int> CreateSetter(this int[] array, int index)
{
return (value) => array[index] = value;
}
}
[TestFixture]
public class ArrayTest
{
[Test]
public void Test()
{
int[] myArray = {21,21,364,658,87};
Action<int> rr = myArray.CreateSetter(1);
rr(500);
Assert.AreEqual(500, myArray[1]);
}
}
When you do this:
int[] myArray = {21,21,364,658,87};
int rr = myArray[1];
rr = 500;
You will only overwrite the value in rr, there is no way for you to get the actual memory address of an arrays inner elements, and thereby updating it.
My answer must therefore be:
myArray[1] = 500;
I'm trying to understand what you're trying to do, if you want to encapsulate your change in a function you could pass the reference on this way, but it's all about what you want to do with it:
public void Proc()
{
var ints = new [] { 1, 2, 3, 4 };
FunctionChangingByReference(ref ints[1]);
}
public void FunctionChangingByReference(ref int x)
{
x = 500;
}
In C# there are no pointers, only references.
(I'm lying a bit, you could use pointers if you create a unsafe context, but we don't do that in C#, and neither should you. When we code C++ we do, but that's C++, and we do it at a cost, we make the code a bit more fragile and error prone. When I code C# I try to optimize the code on a higher level than memory address shuffling. If you really need to optimize on that level you should write the code in C++ and import that code as a dll, then you have a good separation of concern, and don't forget to test drive the development!)
Simply myArray[1] = 500! You could use a property as Nahum Litvin has suggested if you specifically want a reference to a specific integer within the array.
#des answer has awaken my interest. So I tried his solution and it works as expected:
int[] numbers = new[] { 1, 2, 3 };
fixed (int* number = &numbers[0])
{
*number = 10;
}
Console.WriteLine(String.Join(", ", numbers)); // Outputs "10, 2, 3"
You have to compile it with the /unsafe option.
I hope you see that this may bring some problems.
Therefore I don't recommend this solution.
What you want is a basically pointer to a variable.
It's hard to explain the difference between "value type" (like int or struct), a reference and a pointer. I can only recommend learning C.
Here's solution that works, although it may need a lot of changes to your code.
//a class that will hold an int inside
public class myIntWrapper
{
//this is the value wrapper holds
public int theValue;
//constructor taking the value
public myIntWrapper(int argument)
{
theValue = argument;
}
//operator to convert an int into brand-new myIntWrapper class
public static implicit operator myIntWrapper(int argument)
{
return new myIntWrapper(argument);
}
//operator to convert a myIntWrapper class into an int
public static implicit operator int(myIntWrapper wrapper)
{
return wrapper.theValue;
}
}
now you can write:
//create an array -
//setting values to every item in array works
//thanks to operator myIntWrapper(int argument)
myIntWrapper[] myArray = new myIntWrapper[5]{1,2,3,4,5};
//now take a "reference"
myIntWrapper rr = myArray[1];
//change the value
rr.theValue = 500;
//from now on myArray[1].theValue is 500;
//thanks to operator int(myIntWrapper wrapper)
//you can write:
int ss = rr;//it works!
please remember to never do:
rr = 600;
because this will actually create brand new myIntWrapper, that's not "connected" anywhere.
So remember:
rr.theValue = 500;//this changes the value somewhere
rr = myArray[3];//this changes where rr is "pointing" to
Yes, it's quite complicated but I doubt it can be done any simpler without unsafe code. I'm sorry for not explaining it more. I'll answer to all questions in comments.

Reading in a binary file containing an unknown quantity of structures (C#)

Ok, so I currently have a binary file containing an unknown number of structs like this:
private struct sTestStruct
{
public int numberOne;
public int numberTwo;
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
So far, I use the following to read all the structs into a List<>:
List<sTestStruct> structList = new List<sTestStruct>();
while (binReader.BaseStream.Position < binReader.BaseStream.Length)
{
sTestStruct temp = new sTestStruct();
temp.numberOne = binReader.ReadInt32();
temp.numberTwo = binReader.ReadInt32();
temp.numbers = new int[128];
for (int i = 0; i < temp.numbers.Length; i++)
{
temp.numbers[i] = binReader.ReadInt32();
}
temp.trueFalse = binReader.ReadBoolean();
// Add to List<>
structList.Add(temp);
}
I don't really want to do this, as only one of the structs can be displayed to the user at once, so there is no point reading in more than one record at a time. So I thought that I could read in a specific record using something like:
fileStream.Seek(sizeof(sTestStruct) * index, SeekOrigin.Begin);
But it wont let me as it doesn't know the size of the sTestStruct, the structure wont let me predefine the array size, so how do I go about this??
The sTestStruct is not stored in one consecutive are of memory and sizeof(sTestStruct) is not directly related to the size of the records in the file. The numbers members is a reference to an array which you allocate youself in your reading code.
But you can easily specify the record size in code since it is a constant value. This code will seek to the record at index. You can then read one record using the body of your loop.
const Int32 RecordSize = (2 + 128)*sizeof(Int32) + sizeof(Boolean);
fileStream.Seek(RecordSize * index, SeekOrigin.Begin);
If you have many different fixed sized records and you are afraid that manually entering the record size for each record is error prone you could devise a scheme based on reflection and custom attributes.
Create an attribute to define the size of arrays:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
sealed class ArraySizeAttribute : Attribute {
public ArraySizeAttribute(Int32 length) {
Length = length;
}
public Int32 Length { get; private set; }
}
Use the attribute on your record type:
private struct sTestStruct {
public int numberOne;
public int numberTwo;
[ArraySize(128)]
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
You can then compute the size of the record using this sample code:
Int32 GetRecordSize(Type recordType) {
return recordType.GetFields().Select(fieldInfo => GetFieldSize(fieldInfo)).Sum();
}
Int32 GetFieldSize(FieldInfo fieldInfo) {
if (fieldInfo.FieldType.IsArray) {
// The size of an array is the size of the array elements multiplied by the
// length of the array.
var arraySizeAttribute = (ArraySizeAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(ArraySizeAttribute));
if (arraySizeAttribute == null)
throw new InvalidOperationException("Missing ArraySizeAttribute on array.");
return GetTypeSize(fieldInfo.FieldType.GetElementType())*arraySizeAttribute.Length;
}
else
return GetTypeSize(fieldInfo.FieldType);
}
Int32 GetTypeSize(Type type) {
if (type == typeof(Int32))
return 4;
else if (type == typeof(Boolean))
return 1;
else
throw new InvalidOperationException("Unexpected type.");
}
Use it like this:
var recordSize = GetRecordSize(typeof(sTestStruct));
fileStream.Seek(recordSize * index, SeekOrigin.Begin);
You will probably have to expand a little on this code to use it in production.
From everything I have read, the way you are doing it is the best method to read in binary data as it has the fewest gotchas where things can go wrong.
Define your struct like this:
struct sTestStruct
{
public int numberOne;
public int numberTwo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)]
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
And use Marshal.Sizeof(typeof(sTestStruct)).

C# Dynamic Instantiation

I am in need of some help here about doing a dynamic instantiation in C#. What I want to accomplish is to be able to use a string variable that is used as the name in the instantiation. I think you can use reflection or something, but I am lost on this one. Here is my test code snippet and hopefully someone has an answer.
Averages is tied to a class that handles everything. So lets say I wanted to make test the variable and everything that is tied to the string of test could be passed as the instantiation. How could I create an object that can handle the variable test coming in, compile and be used in runtime? I know this may sound out of the ordinary, but instead of me using many IF's with multiple declarations of doubles. I could use a dynamic instantiation. Anyone that can help out I would be most appreciative.
Averages test = new Averages();
double[] testresult;
testresult = test.sma();
womp,,,I want to dynamically declare arrays of doubles. I already know how to declare a static array. What I am trying to accomplish is eliminating declaring 30 arrays that bascially do the same thing over and over again with a different naming.
So instead of doing this:
if (UITAName == "SMA")
{
Averages sma = new Averages();
double[] smaresult;
smaresult = sma.sma(UITAName, YVal, UITPeriod, UITShift);
chart1.Series[UITA].Points.DataBindXY(test2, test1);
}
if (UITAName == "TMA")
{
Averages tma = new Averages();
double[] tmaresult;
tmaresult = tma.tma(UITAName, YVal, UITPeriod);
chart1.Series[UITA].Points.DataBindXY(XVal, tmaresult);
}
else
if (UITAName == "EMA")
{
Averages ema = new Averages();
double[] emaresult;
emaresult = ema.ema(UITAName, YVal, UITPeriod);
chart1.Series[UITA].Points.DataBindXY(XVal, emaresult);
}
I want to do this only once for everything instead of doing IF statements. The problem is that you cannot compile with a declaration of a string. There has to be a way I just do not know how.
Averages UITAName = new Averages();
double[] UITANameresult;
UITANameresult = UITAName.UITAName(UITAName, YVal, UITPeriod);
chart1.Series[UITA].Points.DataBindXY(XVal, UITANameresult);
You can instantiate a class dynamically using Reflection, with Activator.CreateInstance.
Activator.CreateInstance("MyAssembly", "MyType");
However I'm not entirely clear on what you're trying to do. If you already have a class called Averages, what do you need dynamically instantiated? And I'm a bit worried by what you mean that it's "tied to a class that handles everything"...
Sounds like you might need to check out Func<> ??? Just my initial assessment without seeing a little more code to give me a clearer context.
To clarify, if you are wanting to pass the values as an argument, like you would on your command line, then you would need to instance the assembly. Otherwise, with Func<T, TResult> you can pass parameters dynamically to a method and get the return value.
Okay...if I get what you are saying...you want something that would resemble:
class Average
{
public double[] sma()
{
// do something
return dArray;
}
public double[] ema()
{
// do something
return dArray;
}
}
that is...the function 'name' would be the value of the string returned from a database query of some sort?
...and if that is the case then I don't know why you wouldn't just do a dictionary like:
Dictionary<string, double[]> testResults = new Dictionary<string, double[]>();
void GetDoubles(string name, params double[] args)
{
testResult[s] = GetAverages(args);
}
I think this could help you.
If i understand you correctly, you have method initinialization values in db as SMA,EMA,etc and you need to invoke the method at runtime,
string invokeMethod = GetValueFromDB() //ur logic to get the SMA or EMA or TMA from db
Type urType=typeof("yourclassname");
object unKnownObj = Activator.CreateInstance(urType);
//Fill your paramters to ur method(SMA,EMA) here
//ie, sma.sma(UITAName, YVal, UITPeriod, UITShift);
object[] paramValue = new object[4];
paramValue[0] = UITAName;
paramValue[1] = YVal;
paramValue[2] = UITPeriod;
paramValue[3] = UITShift;
object result=null;
try
{
result = urType.InvokeMember(invokeMethod, System.Reflection.BindingFlags.InvokeMethod, null, unKnownObj, paramValue);
}
catch (Exception ex)
{
//Ex handler
}
So this way you can avoid the multiple if loops and will invoke the method directly by the given name..
I think reflection might not be the best solution for your situation. Maybe decomposing your code a little bit might help, something along the following lines...
public interface ICalculation
{
double [] Calculate(double y, double period, double shift);
double XVal {get;}
}
public class SMA : ICalculation
{
public override double[] Calculate( double y, double period, double shift )
{
// do calculation, setting xval along the way
}
// more code
}
public class EMA : ICalculation
{
public override double[] Calculate( double y, double period, double shift )
{
// do calculation, setting xval along the way
}
// more code
}
public class Averages
{
public void HandleCalculation( ICalculation calc, double y, double p, double s )
{
double[] result = calc.Calculate( y, p, s );
chart.Series[UITA].Points.DataBindXY( calc.XVal, result );
}
}

Categories