commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Commons Wiki] Update of "CLI" by Andrew Kutz
Date Sat, 26 Apr 2008 22:45:53 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Commons Wiki" for change notification.

The following page has been changed by Andrew Kutz:
http://wiki.apache.org/commons/CLI

------------------------------------------------------------------------------
  ----
  
  = News =
+ 
+ == Updates on C# port - Unit testing almost complete, and changes ==
+ 
+ The unit tests from 1.1 of CLI have almost all been ported to the C# version. I am happy
to say that the port passes 45/45 of the tests ported so far. The following additional changes
have been implemented in the C# port:
+ 
+ - In C# you cannot access a static method, field, or property accessor from an instance
reference (static or otherwise), hence the following code is illegal:
+ 
+ {{{
+ Option timeLimit = OptionBuilder
+ 	.withLongOpt("limit")
+ 	.hasArg()
+ 	.withValueSeparator()
+ 	.withDescription("Set time limit for execution, in mintues")
+ 	.create("l");
+ }}}
+ 
+ So, in order to maintain elegance I have come up with a solution. I have changed OptionBuilder's
static methods to instance methods, but created a static property accessor called 'Factory'.
Factory is defined as such:
+ 
+ {{{
+ /// <summary>
+ ///		Returns a static instance of OptionBuilder.
+ /// </summary>
+ public static OptionBuilder Factory
+ {
+ 	get { return instance; }
+ }
+ }}}
+ 
+ So the original code now works with one small variation:
+ 
+ {{{
+ Option timeLimit = OptionBuilder.Factory
+ 	.withLongOpt("limit")
+ 	.hasArg()
+ 	.withValueSeparator()
+ 	.withDescription("Set time limit for execution, in mintues")
+ 	.create("l");
+ }}}
+ 
+ - In C# all classes derive from Object, just like Java. Even primitive types are automatically
boxed and unboxed into Object-derived subclasses, just like Java. For a class to be cloneable
it must implement the interface ICloneable and the method 'public object Clone()', just like
Java. However, unlike Java, Object does not implement a shallow clone method. This means that
the logic you implement in your own clone method cannot call the super (or base as it is in
C#) class's Clone method to get a typed, shallow clone. This would not necessarily be a big
deal as you could just create a new class that you are attempting to clone, but if you do
this you would have to be able to clone its properties (assuming they are publicly accessible
or can be set via a constructor) manually -- a cumbersome task.
+ 
+ You see the problem. Option is cloneable, and it relies on the Object's clone method. I
toyed around porting this functionality via two methods. The first method looked like this:
+ 
+ {{{
+ object clone = Activator.CreateInstance( this.GetType(), null );
+ ( clone as Option ).m_alist_values = new List<string>( m_alist_values );
+ return clone;
+ }}}
+ 
+ The above code will not work in all cases, hence I discarded it. The problem is that the
Activator.CreateInstance method's second parameter requires either a null value for a parameterless
constructor, or a parameter array to pass to the constructor of the type you are attempting
to create. As seen in OptionTest.java (and now OptionTest.cs), the DefaultOption class that
extends Option does not implement a parameterless constructor, and in fact does not even override
all of  Option's constructors, just one. So, while using the CreateInstance method *would*
result in the proper object type once cloned, it is cumbersome (although possible) to know
the right constructor parameters to pass to the CreateInstance method. Even if you do figure
out the parameters needed, you still have the task of cloning the new Option's properties,
some of which are not publicly scoped.
+ 
+ Instead, I am serializing the object to be cloned and deserialzing it into a new copy. Like
so:
+ 
+ {{{
+ BinaryFormatter bf = new BinaryFormatter();
+ MemoryStream memStream = new MemoryStream();
+ bf.Serialize( memStream, this );
+ memStream.Flush();
+ memStream.Position = 0;
+ object clone = ( bf.Deserialize( memStream ) );
+ ( clone as Option ).m_alist_values = new List<string>( m_alist_values );
+ return clone;
+ }}}
+ 
+ This method is certainly not as efficient as a simple object creation, but it guarantees
future compatibility with new properties that Option may receive. The only caveat is that
the Option class, and any class that extends it, must implement the attribute [Serializable]
so that it can be serialized:
+ 
+ {{{
+ [Serializable]
+ public class MyOption : Option
+ {
+ ...
+ }
+ }}}
  
  == Release 1.1 Ported to C# ==
  

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message