Friday, April 29, 2005
Mutable Structs
Mutable Structs.
One interesting thing about
But if you do the following with
How does a
A
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:
So what went “wrong” with the above code is when we called
So
The following statment
The moral of the story is don’t use mutable structs. Use a class instead, or return a new struct.
One interesting thing about
struct is when you pass them to an ArrayList. Take a look at this code:using System;The result will be 2 for both as expected. Because Foo is a class, a reference was passed to the
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);
}
}
ArrayList.But if you do the following with
struct, you get an astonishing answer:using System;The value for
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);
}
}
((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_)And when you called the Set method, it looks like this
{
this.x = x_;
}
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 codereturn __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);For a
Console.WriteLine(((Foo)faL[0]).x);
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
That's it!
Send an array of Byte
(1) Call any one of the overloaded members
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:
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;(2) Hook up the delegates and instantiate the objects
SerialPort com1;
serialPortEvents = new WithEvents();(3) Set up a "Settings" button click event to call the Settings dialog like so
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);
Settings frm = new Settings(com1.ConfigFileName, com1.Cnfg);com1.ConfigFileName is defaulted to "Port1.cfg" in its constructor.
frm.ShowDialog();
That's it!
Send an array of Byte
(1) Call any one of the overloaded members
public uint Send(byte chr) ;The return value is the amount of bytes sent.
public uint Send(string s);
public uint Send(byte[] buffer);
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.