Implementing ICloneable While Staying Type Safe

I had always had issue with implementing ICloneable in the .Net Framework on my classes.  Implementing ICloneable requires that you return an Object, but a lot of time you don’t want to return an Object type, you want to return a strongly typed object of type whatever.

Well, thanks to a tip I heard on .NetRocks from Rocky Lhotka, I have coded up an example of how you can a) Implement ICloneable, and b) return a strongly typed object from your Clone method.

Imports System

Public Class BusinessObject
Implements ICloneable
Private Function privateClone() As Object Implements ICloneable.Clone
Dim MyClone As Object = makeClone()
Return MyClone
End Function
Public Function Clone() As BusinessObject
Dim MyClone As BusinessObject = makeClone()
Return MyClone
End Function
Private Function makeClone() As BusinessObject
'*** do the clone here
End Function End Class

The trick is to implement ICloneable as a private function.  To be honest I have no idea why this works.  You would think that implementing the Clone method as a private function would mean that you couldn’t access it, but as the code I wrote below shows, it does work.

imports Microsoft.VisualBasic
imports System
imports System.Collections

public module MyModule
    sub Main
RL()
        dim o as new BusinessObject
        WL("IClone " & o.Clone.IClone)
        WL("StandardClone " & o.Clone.StandardClone)
        dim i as System.ICloneable
        i = ctype(o, System.ICloneable)
        WL("IClone " & ctype(i.Clone,BusinessObject).IClone)
        WL("StandardClone " & ctype(i.Clone,BusinessObject).StandardClone)
        RL()
    end sub

    #region "Helper methods"

    sub WL(text as object)
        Console.WriteLine(text)
    end sub

    sub WL(text as object, paramarray args as object())
        Console.WriteLine(text.ToString(), args)
    end sub
        
    sub RL()
        Console.ReadLine()
    end sub
    
    sub Break()
        System.Diagnostics.Debugger.Break()
    end sub

#end region

end module


public Class BusinessObject
Implements System.ICloneable
    public IClone as string = ""
    public StandardClone as string = ""

Private Function privateClone() As Object Implements ICloneable.Clone
Dim MyClone As Object = makeClone()
        ctype(MyClone,BusinessObject).IClone = "true"
Return MyClone
End Function

Public Function Clone() As BusinessObject
Dim MyClone As BusinessObject = makeClone()
        MyClone.StandardClone = "true"
Return MyClone
End Function

Private Function makeClone() As BusinessObject
'*** do the clone here
        return new BusinessObject
End Function

End Class

I will have to get to the bottom of this private thing.  But at least this will work and do you want expect it to.

Update: I got some answers from a couple people online.
Alvin Bruney (
http://msmvps.com/blogs/Alvin/ ) suggested:

The modify tag, private, does not apply to the compiler. It is capable of
calling the method. The tag is applicable only to calling code.

This I knew, but I guess I was wondering why the compiler allows you to do this.  I guess it makes sense that the interface makes that method public, so public it is!   Case closed

Testing Trackback / Image / File / Google filters.

With this post I am testing out some features of dasBlog.

I am linking to a Trackback faq page by Shai Coggins seen below thanks to the upload image feature (not bad eh?).

It looks like dasBlog just throws these uploaded images into a single folder, which I guess means I could overwrite a file if 2 were uploaded with the same name.  Lemme try…

Yep, it overwrote it.  I guess I will have to be careful about that possible occurance.

On to the file upload option:

Sequencediagram_1.png (1.84 KB)

Interesting, thats pretty cool.

The last thing to test is the content filter ability.

This seems a bit much, you type in a bunch of code and it will output some standard string.  For example, this should produce a google search: $g(chrismay) and this should produce an IMDB search: $imdb(The Matrix).

Here goes…

Update
Well it seems that everything worked pretty well except maybe the trackback isn’t working.  The URL for the trackback appears to not be saved when I save this article, but maybe that is by design.  I will have to look into it.  I posted a comment on the article I was trying to trackback… maybe that output is cached and it will show up later (?), doupt it.  Here is the article I am dealing with.

Indents Fixed!

Well a little tweaking of the code that does the generation of the formatted code, and it now produces what I want:

        Public Shared Function AddTOQueryString(ByVal URL As String, ByVal Key As String, ByVal Value As String) As String
Dim RegExp As New System.Text.RegularExpressions.Regex(Key & "=.*?(&|$)")
Dim Match As System.Text.RegularExpressions.Match = RegExp.Match(URL)
If Match.Success Then
Return RegExp.Replace(URL, Key & "=" & Value & Match.Groups(1).ToString)
ElseIf URL.IndexOf("?") > 0 Then
Return URL & "&" & Key & "=" & Value
Else
Return URL & "?" & Key & "=" & Value
End If
End Function
        /// <summary>Gets or sets the RSS version to write.</summary>
        /// <exception cref="InvalidOperationException">Can't change version number after data has been written.</exception>
        public RssVersion Version
        {
            get { return rssVersion; }
            set
            {
                if(wroteStartDocument)
                    throw new InvalidOperationException("Can't change version number after data has been written.");
                else
                    rssVersion = value;
            }
        }

I am not sure that I like what it does with literal strings.  I will probably want to change that.

I am also now convinced that it will not due for formatting Javascript.  J# just doesn’t share enough similar attributes.  This tool also doesn’t support XML (or HTML), which would be a nice thing too.

This converter looks pretty sweet.  You can include your regions and it will let you keep them collapsed and then expand via javascript, excellent.

I could also just wire up the implementation I already have to deal with HTML and Javascript.

We will see… for now this will do.

HttpFilters, HttpModules, and HttpWastedABunchOfTime

I was just about to make a post talking about the switch over to dasBlog.  I was going to talk about what I liked and didn’t like and whatever, but mostly I was going to talk about the work I have been putting in on writing code that will filter out code and format it nicely.

I wrote and tested an HttpModule which loads a Reponse Filter that parses the Html looking for <code> tags and formats the code inside those nicely.

So I go to write my first post, and I am looking for a hyperlink button in the texteditor, but instead I see this icon that look like a C# file.  “No, I did not just waste all that time” I thought. 

public bool IsTimeWasted(String name){
    return true;
}

Public Function IsWasted(ByVal time As TimeSpent) As Boolean
  If time IsNot Nothing Then
    Return True
  Else
    Return False
  End If
End Function

var s;
s = ‘asdf’;
document.getElementById(“asdf”); /* comment */

SELECT * FROM
ThingsToDo
WHERE
WastedTime <> 1
AND
Task = ‘Writing HttpFilter’

0 rows returned

So you can see I basically wasted my time doing all that.

This tool doesn’t provide an HTML code type, and I used J# in place of Javascript, but it works ok I guess.

The on thing it is really lacking is that it doesn’t maintain indents!?!?  I manually restored the indents above, otherwise my vb code would look like this:

Public Function IsWasted(ByVal time As TimeSpent) As Boolean
If time IsNot Nothing Then
Return True
Else
Return False
End If
End Function

Which is weird, b/c it looks fine in the preview window… I will have to look into that.

 

 

dasBlog and httpfilters

Apparently there is a cool blogging app called dasBlog, which means “That Blog” in German :), that provides a lot of better features when compared with my old blogX, and even better it provides a direct upgrade from blogX, so I don’t have to write my own scripts to do the conversion to what I was going to use (newblog on DNN).

The downside is that I had already written the necessary code to parse and replace … well… “code”… in my blog posts into pretty formatted HTML.

It worked like this… I would type something like

Dim s as New System.Text.StringBuilder 

and it comes out looking like:

.csharpcode
{
font-size: small;
color: black;
font-family: Courier New , Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}

.csharpcode .lnum { color: #606060; }

Dim s as New System.Text.StringBuilder 

So that is pretty cool… but I think I can get the same result, and maybe make it even cleaner, by using an httpfilter.

HttpFilters are registered at application startup and are sent the html just before it gets passed to the browser, so you can use the filters as like a last change modification mechanism. Hopefully I can write some regexps to parse out what I want and replace it with the new stuff.

Format String

The following content has been cut and pasted from Kathy Kam’s Blog. The article was Format String 101.

 

I see stuff like {0,-8:G2} passed in as a format string. What exactly does that do?” — Very Confused String Formatter

The above format can be translated into this:

“{<argument index>[,<alignment>][:<formatString><zeros>]}”

argument index: This represent which argument goes into the string.

String.Format(“first = {0};second = {1}”, “apple”, “orange”);

String.Format(“first = {1};second = {0}”, “apple”, “orange”);

 

gives the following strings:

 

“first = apple;second = orange”

“first = orange;second = apple”

 

alignment (optional): This represent the minimal length of the string.

Postive values, the string argument will be right justified and if the string is not long enough, the string will be padded with spaces on the left.

Negative values, the string argument will be left justied and if the string is not long enough, the string will be padded with spaces on the right.

If this value was not specified, we will default to the length of the string argument.

 

String.Format(“{0,-10}”, “apple”);      //”apple     “

String.Format(“{0,10}”, “apple”);       //”     apple”

format string (optional): This represent the format code.

Numeric format specifier is available here. (e.g. C, G…etc.)
Datetime format specifier is available here.

Enumeration format specifier is available here.

Custom Numeric format specifier is available here. (e.g. 0. #…etc.)

 

Custom formatting is kinda hard to understand. The best way I know how to explain something is via code:

 

int pos = 10;

int neg = -10;

int bigpos = 123456;

int bigneg = -123456;

int zero = 0;

string strInt = “120ab”;

 

String.Format(“{0:00000}”, pos);      //”00010″

String.Format(“{0:00000}”, neg);      //”-00010″

String.Format(“{0:00000}”, bigpos);   //”123456″

String.Format(“{0:00000}”, bigneg);   //”-123456″

String.Format(“{0:00000}”, zero);     //”00000″

String.Format(“{0:00000}”, strInt);   //”120ab”

String.Format(“{0:#####}”, pos);      //”10″

String.Format(“{0:#####}”, neg);      //”-10″

String.Format(“{0:#####}”, bigpos);   //”123456″

String.Format(“{0:#####}”, bigneg);   //”-123456″

String.Format(“{0:#####}”, zero);     //””

String.Format(“{0:#####}”, strInt);   //”120ab”

 

While playing around with this, I made an interesting observation:

 

String.Format(“{0:X00000}”, pos);      //”A”

String.Format(“{0:X00000}”, neg);      //”FFFFFFF6″

String.Format(“{0:X#####}”, pos);      //”X10″

String.Format(“{0:X#####}”, neg);      //”-X10″

 

The “0” specifier works well with other numeric specifier, but the “#” doesn’t. Umm… I think the “Custom Numeric Format String” probably deserve a whole post of it’s own. Since this is only the “101” post, I’ll move on to the next argument in the format string.

 

 

zeros (optional): It actually has a different meaning depending on which numeric specifier you use.

 

int neg = -10;

int pos = 10;

 

// C or c (Currency): It represent how many decimal place of zeros to show.

String.Format(“{0:C4}”, pos);      //”$10.0000″

String.Format(“{0:C4}”, neg);      //”($10.0000)”

 

// D or d (Decimal): It represent leading zeros

String.Format(“{0:D4}”, pos);      //”0010″

String.Format(“{0:D4}”, neg);      //”-0010″

 

// E or e (Exponential): It represent how many decimal places of zeros to show.

String.Format(“{0:E4}”, pos);      //”1.0000E+001″

String.Format(“{0:E4}”, neg);      //”-1.0000E+001″

 

// F or f (Fixed-point): It represent how many decimal places of zeros to show.

String.Format(“{0:F4}”, pos);      //”10.0000″

String.Format(“{0:F4}”, neg);      //”-10.0000″

 

// G or g (General): This does nothing

String.Format(“{0:G4}”, pos);      //”10″

String.Format(“{0:G4}”, neg);      //”-10″

 

// N or n (Number): It represent how many decimal places of zeros to show.

String.Format(“{0:N4}”, pos);      //”10″

String.Format(“{0:N4}”, neg);      //”-10″

 

// P or p (Percent): It represent how many decimal places of zeros to show.

String.Format(“{0:P4}”, pos);      //”1,000.0000%”

String.Format(“{0:P4}”, neg);      //”-1,000.0000%”

 

// R or r (Round-Trip): This is invalid, FormatException is thrown.

String.Format(“{0:R4}”, pos);      //FormatException thrown

String.Format(“{0:R4}”, neg);      //FormatException thrown

 

// X or x (Hex): It represent leading zeros

String.Format(“{0:X4}”, pos);      //”000A”

String.Format(“{0:X4}”, neg);      //”FFFFFFF6″

 

// nothing: This is invalid, no exception is thrown.

String.Format(“{0:4}”, pos));      //”4″

String.Format(“{0:4}”, neg));      //”-4″

 

In summary, there are four types of behaviour when using this <zeros> specifier:

Leading Zeros: D, X

Trailing Zeros: C, E, F, N, P

Nothing: G

Invalid: R, <empty>

 

Now, that we’ve gone through the valid specifiers, you can actually use this in more than just String.Format(). For example, when using this with Byte.ToString():

 

Byte b = 10;

b.ToString(“D4”);      //”0010″

b.ToString(“X4”);      //”000A”

 

Wow… this was way longer than I expected. The BCL team is having blog day today, I need to get back to posting something for the BCLWeblog.

<Editorial Comment>

One of the lesson I learnt from an earlier post is that, readers are not interested in a post that doesn’t give you more information than what MSDN provides. Instead, readers are more interested in seeing stuff that are not available on MSDN. So when I was doing research to post about this topic, I found that MSDN actually talks about exactly what the {0,-8:G2} format does. It is just not easy to find nor centrally located.

For example, in the ToString MSDN Doc, the “Remarks” section covered some basic rules on what a “format string” is. In the String.Format MSDN Doc, the “Remarks” section actually have a pretty detail explaination of what the above format does. Furthermore, MSDN provides a format string overview as well as a the table that specifies all the values that are allowed.

This puts me in an interesting position when writing about this topic. MSDN actually have lots of info that cover it. But since I have also heard more than one person being confused about this topic, I decided to post a summary of the documents and more examples. Do you think this is useful? Should I just stick to posting exclusively on non-MSDN topics?

</Editorial Comment>