Friday, April 29, 2005

 

Mutable Structs

Mutable Structs.

One interesting thing about struct is when you pass them to an ArrayList. Take a look at this code:
using System;
using System.Collections;

public class MutableStruct
{

class Foo
{
public int x;

//public Foo() { x = -1; }

public void Set(int x_)
{ x = x_; }
}

public static void Main()
{
Foo[] fa = new Foo[10];

fa[0] = new Foo();
fa[0].Set(2);


Console.WriteLine(fa[0].x);

// Set an ArrayList of Foo
ArrayList faL = new ArrayList();

faL.Add(new Foo() );
((Foo)faL[0]).Set(2);

Console.WriteLine(((Foo)faL[0]).x);

}
}
The result will be 2 for both as expected. Because Foo is a class, a reference was passed to the ArrayList.

But if you do the following with struct, you get an astonishing answer:
using System;
using System.Collections;

public class MutableStruct
{

struct Foo
{
public int x;

//public Foo() { x = -1; }

public void Set(int x_)
{ x = x_; }
}

public static void Main()
{
Foo[] fa = new Foo[10];

fa[0] = new Foo();
fa[0].Set(2);


Console.WriteLine(fa[0].x);

// Set an ArrayList of Foo
ArrayList faL = new ArrayList();

faL.Add(new Foo() );
((Foo)faL[0]).Set(2);

Console.WriteLine(((Foo)faL[0]).x);

}
}
The value for ((Foo)faL[0]).x was 0 instead of the expected 2. What went “wrong”?

How does a struct differ from a class?

A struct is a value type. What this means is that the object of a struct is placed on the program stack instead of in the heap. This also means that when you copy a struct, or when you assign an object of a struct to another, or when you pass it as an argument to a method, a copy is made. This is in contrast with a class, because with a class, a reference (a pointer) is passed.

However, when you called the Set method of the struct, a secret "ref this" was passed to the method, allowing you to mutate the value of the struct. (This is what mutable struct means). So (this is my interpretation) the actual Set method looks like this:
public void Set(ref this, int x_)
{
this.x = x_;
}
And when you called the Set method, it looks like this fa[0].Set(fa[0], 2). In this case a reference of the struct object (fa[0] is the reference to the first struct object in the Foo array) was passed into the Set method.

So what went “wrong” with the above code is when we called ((Foo)faL[0]).Set(2);, we first invoke the indexer of the ArrayList object, which is nothing but the get/set assessors method. The get method will probably have the following code
return __someObject[indexOfArray];
When this occur, a copy of the Foo object is made. Just like any normal method that returns a value, the value is first copied to a temporary variable and returned.

So faL[0] returns a copy of our Foo object. When we attempt to call the method ((Foo)faL[0]).Set(2). This method will then jam the value 2 into the copied version of our object. Then when the the ((Foo)faL[0]).Set(2); method returns, the copy is destroyed.

The following statment Console.WriteLine(((Foo)faL[0]).x); will yield an value of 0 because the original ((Foo)faL[0]).x hasn’t changed a bit. (A copy of it was returned at both instances:
((Foo)faL[0]).Set(2);
Console.WriteLine(((Foo)faL[0]).x);
For a class Foo a reference was returned instead, allowing us to change its field.

The moral of the story is don’t use mutable structs. Use a class instead, or return a new struct.

Friday, April 22, 2005

 

Trace.Listeners.Clear()

Do not call Trace.Listeners.Clear(), as this will clear of all Debug.Assert() warning messages as well.

Sunday, April 17, 2005

 

Convert integer to binary

To convert any integer to binary (hex or any supported bases). Do teh following:
int number = 32;
Convert.ToString(number, 2);

 

ArrayList.ToArray Method

In order to convert an ArrayList collection to a regular array do the following. (Say you have an ArrayList object called someArrayList and you want to convert it to an array of ints)
int[] intArray = (int[]) someArrayList.ToArray(typeof(int));
I got this help from http://www.lazycoder.com/weblog/arraylisttoarray/

Friday, April 15, 2005

 

Serial Communcation using SerialComm library

Download the source code from http://www.codeproject.com/dotnet/DotNetComPorts.asp

The idea behind Serial port.

In order to use a com port, we instatiate an obect of SerialPort.

The class SerialPort defines several events that we can handle via delegates. This is encapsulated in the WithEvents class. The one-argument constructor of SerialPort takes in an object of WithEvents class.

Prior to using reading or writing to a comm port, the port must be opened via the SerialPortObject.Open(1) method. This method takes in a dummy index (but doesn't really do anything to the index).

The default port configuration for SerialPort resides in the SerialCnfg class. But the best way to configure the port is via the Settings dialog box. This dialog box will automatically serialize the values so that we can use it a second time. If no values are provided, SerialCnfg will use its defaulted value (9600 bps, no hardware handshake, no parity).

Steps to Initiaze the SerialPort

(1) Declare an WithEvent and SerialPort objects
WithEvents serialPortEvents;
SerialPort com1;
(2) Hook up the delegates and instantiate the objects
serialPortEvents = new WithEvents();
serialPortEvents.Error = new StrnFunc(this.OnError);
serialPortEvents.RxChar = new ByteFunc(this.OnRecvI);
serialPortEvents.CtsSig = new BoolFunc(this.OnCts);
serialPortEvents.DsrSig = new BoolFunc(this.OnDsr);
// Get a connection
com1 = new SerialPort(serialPortEvents);
com1.Open(1);
(3) Set up a "Settings" button click event to call the Settings dialog like so
Settings frm = new Settings(com1.ConfigFileName, com1.Cnfg);
frm.ShowDialog();
com1.ConfigFileName is defaulted to "Port1.cfg" in its constructor.

That's it!

Send an array of Byte

(1) Call any one of the overloaded members
public uint Send(byte chr) ;
public uint Send(string s);
public uint Send(byte[] buffer);
The return value is the amount of bytes sent.

That's it!

Receive stuff

Receiving stuff is a bit tricky because there are two ways to receive -- via pooling the com port or via delegate. I’d recommend the delegate method.

This is what you do

(1) Check the OnEvent Receive Mode in the Settings dialog box.

THat's it!

The method delegate you hooked up in the serialPortEvents.RxChar like so:
serialPortEvents.RxChar = new ByteFunc(OnRecvI);
will be called. THe method, like so
void OnRecvI(byte[] byteReceived)
will be called whenever an incoming byte its received.

This page is powered by Blogger. Isn't yours?