Want to follow this site? Here's the RSS feed.

Video 1 (FWD) - "Setting up your Firefox Development Environment"

Saturday, December 31, 2005

Finally! Here's the long awaited part 1 of my Firefox for ASP.NET 2.0 Developers Video Series. I will be releasing more parts to the series over the next few weeks.

This video is titled "Setting up your Firefox Development Environment" and contains valuable information on setting up your web development environment for maximizing efficiency. More setup information relating to this video will be mentioned in future videos as the utilities used in future videos of course also require setup.

Furthermore, this video is valuable not only to the professional web developer (as well as the non-professionals who still use tables for layout), but it's also valuable for anyone interested in maximizing their web experience.

Below is the link to part 1 of the Firefox for ASP.NET 2.0 Developers video series. You can download Visual Web Developer 2005 Express and Firefox 1.5 below as well.

(0 Comments)

Firefox for ASP.NET 2.0 Developers Video Series

Thursday, December 8, 2005

In September I recorded a video series I entitled the Firefox Web Developer Series. I've since renamed it to the Firefox for ASP.NET 2.0 Developers Video Series (clearly because the original title wasn't long enough). I put the project on hold because of the .NET 2.0 course I was teaching, which took almost all my time, but now I'm ready to take the time to get back into videos.

This series is for ASP.NET 2.0 developers who want to enhance their ECMAScript (JavaScript) skills and see how the powerful web development suite known as Firefox as simplify their lives as much as .NET 2.0 Framework does. In the series I use Beta 2 of Visual Web Developer 2005 and Firefox 1.0, but everything should be good for the final version of VWD2005 and for Firefox 1.5.

I will be releasing videos from this series over the next few weeks. For now, here is my introduction.

You can download the first video from the video below. You can download Visual Web Developer 2005 Express and Firefox 1.5 below as well.

(0 Comments)

try{}catch{} in .NET 2.0 - Note

Thursday, December 8, 2005

Here is a comment Joe made about my previous post.

... One additional facet that will probably go (mostly) unnoticed is that you can throw exceptions across assembly boundaries, and the wrapping will occur based on the assembly-level attribute on the assembly whose catch block is being evaluated. This makes interoperability with code that isn't on the wrapping plan, e.g. COBOL or Eiffel, work seamlessly as you would expect.

...

This comment is rather hidden in how I have my page designed, but I thought it worthy of it's own posting anyhow.

(0 Comments)

try{}catch{} in .NET 2.0 - Part 2

Monday, December 5, 2005

As I pointed out in a previous entry, try{}catch{} works differently in .NET 2.0 as it does in .NET 1.x. In 2.0, non-exception "throwables" are wrapped in a RuntimeWrappedException which can be caught by try{}catch(Exception ex){}, while, to catch then in .NET 1.x, you were required to use try{}catch{}. This led me to wonder 1) how does this work? and 2) is there even a purpose for try{}catch{} anymore?

So I started my research by... well, passing the buck, or going to the source, depending on your view on things. The first thing I did was ask Brad Abrams if he had some insights about this. He then forwarded me to Jonathan Keljo who I guess then forwarded me to Joe Duffy...sheesh what a line up! The best of the best of the best right there! Goodness, I feel like an ant...

Anyhow... here's the thing. Joe affirmed that there are at least two purposes for try{}catch{} in .NET 2.0

Here are his exact words...

(1) If your assembly doesn't have "wrapping" turned on;

(2) If you don't care to access the exception information via a variable. This can help to reduce the temptation to accidentally do a catch(Exception e){ /*...*/; throw e; } when you meant to do catch { /*...*/ throw; }.

OK cool, now what about the mechanics? Joe explains that the wrapping of RuntimeWrapperException around non-exception throwables is due to the fact that C# and VB auto opt-in all assemblies to what they call "the wrapping plan". This means there is a RuntimeCompatibilityAttribute(...) on the assembly where, in this case, WrapNonExceptionThrows=true is set. When this is the case all non-System.Exception "exceptions" get wrapped into a RuntimeWrappedException, which, as Joe points out of course does inherit from System.Exception. Conversely, if WrapNonExceptionThrows=false is set, then there is no magical wrapping.

Let's see this all in action. But before we do, last time I wrote about this I forgot to what mention happens when you compile the below code (this is the same code from the previous blog entry about this topic)

// ThrowerHarness.cs
namespace ThrowerExample
{
    class ThrowerHarness
    {
        static void Main(string[] args) {
            try {
                Thrower.ThrowException( );
            }
            catch (System.Exception ex) {
                System.Console.WriteLine("System.Exception error: " + ex.Message);
            }
            catch {
                System.Console.WriteLine("Non System.Exception based error.");
            }

            try {
                Thrower.ThrowString( );
            }
            catch (System.Exception ex) {
                System.Console.WriteLine("System.Exception error: " + ex.Message);
            }
            catch {
                System.Console.WriteLine("Non System.Exception based error.");
            }
        }
    }
}

Compiling this code actually gives the following warnings...

throwerlib.cs(16,7): warning CS1058: A previous catch clause already catches all
        exceptions. All non-exceptions thrown will be wrapped in a
        System.Runtime.CompilerServices.RuntimeWrappedException
throwerlib.cs(29,7): warning CS1058: A previous catch clause already catches all
        exceptions. All non-exceptions thrown will be wrapped in a
        System.Runtime.CompilerServices.RuntimeWrappedException

As you can see, we know at compile that try{}catch(Exception ex){} will grab the exceptions.

Here's the IL we are using, which contains the Thrower class and is referenced by the C# application.

// ThrowerLib.il
.assembly ThrowerLib { }

.class public Thrower {
    .method static public void ThrowException( ) {
        ldstr "ThrowException exception from the IL world!"
        newobj instance void [mscorlib]System.Exception::.ctor(string)
        throw
        ret
    }

    .method static public void ThrowString( ) {
        ldstr "Weird exception!"
        throw
        ret
    }
}

Of course, there's our command syntax...

ilasm /t:dll ThrowerLib.il
csc Thrower.cs /r:ThrowerLib.dll

After a successful assembly and compilation, running this application gives the following output...

System.Exception error: ThrowException exception from the IL world!
System.Exception error: An object that does not derive from System.Exception has been wrapped in a RuntimeWrappedException.

Now, what about what Joe was saying about the RuntimeCompatibilityAttribute? Well, if we were to tack the following onto our existing class, we would get absolutely no warnings. Pretty cool...

using System.Runtime.CompilerServices;
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = false)]

Not only that, but here's the output as we would expect.

System.Exception error: ThrowException exception from the IL world!
Non System.Exception based error.

As you can see it did not wrap the exception. So, now, the picture of how things work and how to modify them is a bit more complete.

You can download the code for this entry by the link below.

Joe Duffy also has an explanation of this, although his is from the Beta 2 era (I only see one change -- WrapNonClsExceptions -> WrapNonExceptionThrows; but there may be more). Here is his article.

(6 Comments)

MSDN Nuggets WCF Mania!

Sunday, December 4, 2005

I just did my weekly check of the MSDN nuggets page and found that Mike Taulty has been hard at work. He just released 6 more WCF videos.

  • Message Encoding
  • Message Patterns
  • Sessions
  • Instancing
  • Concurrency
  • Exceptions

Given the great quantity and quality of videos out there on WinFX technologies there is absolutely no reason people can't learn these new technologies. You don't need to read books, study whitepapers, or listen to those Geneva-convention-violating boring webcasts, all you have to do it click and pay attention. It's as if osmosis truely is a viable way of learning!

You can access these videos at the below link.

MSDN Nuggets

(3 Comments)

XHTML 1.1 Escaping (Chapter Excerpt 3)

Sunday, December 4, 2005

One thing you will inevitably notice when working with the ultra strict XHTML 1.1 is how the ampersand (&) works. In HTML you never had to worry much about the ampersand, though you could use it to implant an HTML space ( ). Now given that XHTML is XML, you simply can't get by with the rules of HTML. In the XML world, if you want to save an XML document with an ampersand, then you have to escape it. If you are familiar with C-based programming languages, then you know all about special characters like this. In those languages you have to "escape" certain characters such as the backslash (\), with another backslash.

In fact, in Altova's XMLSpy application you will get a stopping warning if you have XML that looks something like <b>&</b>. The appropriate way to have an ampersand in XML is to write it as &amp;. This is very similar to what you could do with the   space in HTML and it's not that far off from what we already do. For instance, if you wanted to write &nbsp;. In fact if you want to write &amp;nbsp; you have to write &amp;amp;nbsp. So, if you know HTML, you already know the fundamentals of this rule. It's just that in the strict world of XHTML 1.1, you can no longer let little mistakes enter your code.

Now this rule about dealing with ampersands doesn't end with standalone ampersands, but also applies to ampersands in links. For instance, you can't just have a link like default.aspx?id=3&category=5. Your link has to transform to default.aspx?id=3&category=5.

Fortunately ASP.NET 2.0 is smart enough to deal with things like this in your databinding. For instance, look at the following code...

ASP.NET 2.0 Code

<asp:GridView ID="gvLinks" runat="server"></asp:GridView>

Code Behind

C#

String[] links = new String[] { "http://jampad.net/default.aspx?id=1&name=2", "http://jampad.net/default.aspx?id=1&name=2&frog=3", "Amburgers & Wootbeer" };
gvLinks.DataSource = links;
gvLinks.DataBind( );

Believe it or not, ASP.NET will output produce the following...

<table cellspacing="0" rules="all" border="1" id="gvLinks" style="border-collapse: collapse;">
    <tr>
        <th scope="col">Item</th>
    </tr>
    <tr>
        <td>http://jampad.net/default.aspx?id=1&amp;name=2</td>
    </tr>
    <tr>
        <td>http://jampad.net/default.aspx?id=1&amp;name=2&amp;frog=3</td>
    </tr>
    <tr>
        <td>A&W</td>
    </tr>
</table>

While I'm not a big fan of looking at table code, I am however a huge fan of automation. As you can see here, you don't have to fight with manually escaping data binding ampersands. Thus, you can give ampersands in XHTML data binding a vote towards deterministic.

(0 Comments)

XHTML 1.1 and DataBinding (Chapter Excerpt #2)

Sunday, December 4, 2005

When doing serious data binding in ASP.NET you may want to reconsider using XHTML 1.1 or XHTML 1.0 Strict at all. The rule is simple: use the document type that can be deterministicly proven to be proper in your situation. Put another way, unless you have deterministicly proven that there will never be any invalid markup in the data, you should always use XHTML 1.0 Transitional.

If the binding data has some odd markup, then you will end up sending invalid XHTML 1.0 sent to IE breaking validation or sending invalid XHTML 1.1 markup to browsers such as Firefox, halting the rendering.

But what does it mean to be deterministicly proper? To put it simply it means to absolutely garuntee that the data will always be proper, that is, to be able to always predict the properness of data. This does not mean "well, it worked for 100,000 tests, so it's good enough", but rather it means that it absolutely will always work 100% of the time. You can get this level of determinism by looking at the symantics of what is going to be bound. For example, if you are binding a table with numbers, which will always be numbers, then you should have a level of determinism here. However, if you are binding a table with unvalidated under input, then you do not have determinism as you have no idea what a user will input. The user could input <b><i></b></i>, which will break the page. You have no idea. Having a proven, not demonstrated, view of data is what this is all about.

Here are a few guidelines that should help you with determining what is and not deterministic.

These things are never deterministic...

  • Unvalidated user input
  • Unvalidated external data
  • HTML
  • Anything else with angle brackets (<, >), except wellformed XML

Given symantical care, these things should be deterministic...

  • Wellformed XML
  • Alphanumeric strings
  • Base64 encoded data
  • Alphanumeric strings

To reiterate: only use the document type that is deterministicly proven to always be proper.

(0 Comments)

Excerpts from my XHTML 1.1 Chapter

Friday, December 2, 2005

One of the great things about XHTML 1.1 is that you are never allowed to serve it's content as text. You can send every type of XHTML 1.0 as text all day long, but never XHTML 1.1. You say you never send as text anyhow? Sure you do... that's what the text/html content-type is all about. The default for every web server (that I know of) is to send "browser" content (i.e. HTML, XHTML) as the text/html content-type. To use a different content-type you have to specifically say so.

The typical way to send XHTML 1.1 content is actually with the application/xhtml+xml content-type. To server a page using this type in .NET, you simply state the following in the early parts of your .NET page rendering (at the Init or Page events).

C#

Response.ContentType = "application/xhtml+xml";

VB2005

Response.ContentType = "application/xhtml+xml"

When you do this, you kick modern web browsers, like Firefox, into what I like to call "parsing mode", "ultra strict mode", or "application mode" depending on my mood, but what it really is is XML parsing mode. In my lectures I often say "HTML is fundamentally unparsable". What I really mean is "HTML is fundamentally unparsed". That is, browsers tokenize HTML (via scanning), rather than parse it via XML parsing. Not to say that web browsers parse XML per se, but they could fundamentally do so it they wanted to. XHTML is XML and therefore "XHTML is parseable". Kicking modern web browsers into this ultra strict mode actually forces the browser to parse the page in an XML centric manner. What's this mean? It means that if your XML (XHTML) is not well-formed, it will throw an error. It's important to note that when you are in this ultra strict mode, the browser is not a validator (that would be REALLY cool), but is more of a well-formedness checker and is the closest things we have to a runtime compiler (which, I know, seems like an oxymoron.)

So, why do this work to get this ultra strict mode? For one simple reason: QA! Quality assurance requires that you take your work seriously. You can't just throw together a bunch of pages and throw them out on the web. If you were writing C#, C++, or Java you would be forced to run your code through a compiler to check for errors. By using ultra strict XHTML mode, you again get this forced compliance.

One word of caution...and it's a common word of caution. Gosh, no matter what I say or what I do on the web it always seems to be the same word of caution: this doesn't work in IE! This is because IE, by default, has absolutely no idea what application/xhtml+xml is. If you try to send this type of content to IE, it will probably try to download the file locally. Now there are times when it will load fine, but what usually is happening in these cases is that the content type is specified in the Windows registry to tell IE how to render it. Since we are talking about the web here, and not the Intranet world we have to follow the universal rules of the W3C, ECMA, and...well least common modern denominators (I throw the word modern in there just in case anyone wants to say that Netscape Communicator 4 is the LCD...and for the record, I don't care about any 4th generation browsers.)

So we need to make sure that IE doesn't get this ultra strict content type. Consequently, we won't have ultra strict mode in IE. Now, if you're paying attention at all you will notice that we have a page with at least two content-types required to support two different planets of browsers (IE, the rest of Earth). You can't send two at the same time. Not a problem. All we need to do is whip out a quick condition based upon what the browser can and cannot do.

When it comes to server-side browser detection some people like like to rely on the UserAgent string of the browser. This is actually a very bad idea due to how easy it is to modify a browser's UserAgent string (especially in IE with all the IE toolbars out there!). I actually read somewhere where someone said that "using the UserAgent is the fastest way to hell" I'd have to go along with that hyperbole.

Here's what you really do: test if the browser can accept the application/xhtml+xml content-type. If they can use it, use it. If not, don't. That's all there is to it, but before I get into the code there's one more thing. We're not talking just about the content-type here, were also talking about the document type (the DTD). If the condition comes back negative, that is, it does not accept xhtml+xml, then you can't use XHTML 1.1 either. So you also have to control the content-type nad the document type in the same shot. This is also not a problem.

Here's a standard method I use in the pages I want to be in ultra strict mode.

In the ASP.NET page, I replace the doctype with the following.

<asp:literal id="litDoctype" runat="server"></asp:literal>

Now in the code-behind I do the following...

C#

Boolean debugMode = false;
private void SetDoctype( ) {
    Boolean mimeTypeOverride = false;
    if (Request.QueryString["xhtml"] != null && Request.QueryString["xhtml"] == "1") {
        mimeTypeOverride = true;
    }

    Boolean realBrowser = false;
    if (Request.ServerVariables["HTTP_ACCEPT"] != null || mimeTypeOverride) {
        String httpAccept = Request.ServerVariables["HTTP_ACCEPT"];
        if (httpAccept != null && httpAccept.IndexOf("application/xhtml+xml") > -1 || mimeTypeOverride) {
            realBrowser = true;
        }
    }

    if (realBrowser && !debugMode) {
        Response.ContentType = "application/xhtml+xml";
        litDoctype.Text = "";
        litDoctype.Text = "\n";
        litDoctype.Text += "\n";
    }
    else {
        Response.ContentType = "application/xml";
        litDoctype.Text = "\n";
    }
}

VB2005

Dim debugMode As Boolean = False
Sub SetDoctype()
    Dim mimeTypeOverride As Boolean = False

    If Request.QueryString("xhtml") <> Nothing And Request.QueryString("xhtml") = "1" Then
        mimeTypeOverride = True
    End If

    Dim realBrowser As Boolean = False
    If Not (Request.ServerVariables("HTTP_ACCEPT") Is Nothing) Or mimeTypeOverride Then
        Dim httpAccept As String = Request.ServerVariables("HTTP_ACCEPT")
        If Not (httpAccept Is Nothing) And httpAccept.IndexOf("application/xhtml+xml") > -1 Or mimeTypeOverride Then
            realBrowser = True
        End If
    End If

    If realBrowser And Not debugMode Then
        Response.ContentType = "application/xhtml+xml"
        litDoctype.Text = ""
        litDoctype.Text = "" & vbNewLine
        litDoctype.Text += ""
    Else
        Response.ContentType = "application/xml"
        litDoctype.Text = ""
    End If
End Sub

This code is actually longer than you might expect, but this version is a bit more robust than a simple condition. The first to notice about this code is obvious: it checks to see if the browser can accept the application/xhtml+xml content type by checking the HTTP_ACCEPT server variable. Depending on the result, the browser either gets application/xhtml+xml content type and the XHTML 1.1 doctype or text/html content type and XHTML 1.0 Transitional.

Secondly, as you can also see, I've included a debug mode which, if set to true, will tell the page to serve the "less-strict" doctype. This comes in handy when you want to make sure you get the "less-strict" doctype. I'm using a private class boolean field named debugMode as a means to put the entire page into debugMode. You could also use a query parameter to put just this one part into debug mode.

Finally, you can see something rather odd towards the beginning of the code. Even though we are doing all of this to guarantee well formed XML, this does not in any way give us any information about validation. That's where this other part comes in. If you were go point the W3C validator at this page it would actually get the XHTML 1.0 Transitional doctype with the text/html content-type. That's all well and good for validating against that doctype, but you technically have two different versions of the same page here. You need to validate against the XHTML 1.1 version as well. So, with the inclusion of a quick query parameter check I'm allowing for the ability to give the W3C validator a Url such as default.aspx?xhtml=1 which will force the page to be in XHTML 1.1 mode. This is a little easier than always having to tell the W3C validator the XHTML 1.1 override (I never much liked the warning it gives you anyways when you do it their way anyhow). As I mentioned previously, you could use a similar technique for for it into the "less-strict" mode. One idea would be to set default.aspx?xhtml=0 to kick in "less-strict" mode.

(0 Comments)

Gosh I hate SPs/SQL (a.k.a. LLBLGen Rocks!)

Friday, December 2, 2005

...well at least in my C# code. That stuff belongs in the world of reporting, integration services, and other places which are NOT IN CODE. You couldn't get me to use ADO.NET anymore; it's such a pain for large projects. I love it for mass importing and when I do extremely dynamics such as report generation and a few other things, but for a static data access teir it's PATHETIC.

Not only is everything you type not strongly typed and therefore prone to error and has no color syntax; SQL (including SP calls) is just abrupt. You are doing this beautiful array of C# 2.0 greatness. Generic collections all over and BAM you see "select * from Person where..." Yuck!

Long live LLBLGen! If you don't know what LLBLGen is, you are completely missing out. I've been using it for months on all my projects and it's just downright awesome. It's basically LINQ...NOW. It allows you to use strongly typed .NET code to access your data WITHOUT writing any data tier code yourself. Not only that, the full blown enterprise edition is only $300. There is NO reason to ever write any data access layer yourself. It will pay for itself in about a DAY. I recommending getting a copy of LLBLGen even for your HOME projects!

All you have to do is point the LLBLGen app to the database, select the tables (and other entities) you want, and hit generate. It automatically creates a Visual Studio 2005 (or 2003 if you HAVE to use that icky thing) project for you. You can either include that project into your solution or compile the assembly and just us the compiled files. You only need to use LLBLGen again when you schema changes, which, as every architect knows...shouldn't be happening that often.

This rant is brought to you by the following sponsor...

DataSet dataSet1 = new DataSet( );
SqlDataAdapter sqlDataAdapter1 = new SqlDataAdapter( );

SqlConn1 = new SqlConnection(connString);
SqlConn1.Open( );

SqlCommData = new SqlCommand("GetDraftBox", SqlConn1);
SqlCommData.CommandType = CommandType.StoredProcedure;

sqlDataAdapter1.SelectCommand = SqlCommData;
sqlDataAdapter1.Fill(dataSet1, "MailList");

return dataSet1;
I was porting this old app from .NET 1.x to .NET 2.0 and I kept seeing stupid garbage like this. I got SO sick of it I decided to disconnect the logic tier and connect it to the LLBLGen access layer. Here's what I have now...
DraftMailCollection draftMailBox = new DraftMailCollection( );
draftMailBox.GetMulti(null);
return draftMailBox;

THAT'S IT!!! Short, sweet, strongly-typed, intellisense LOVES it, it's pretty (you gotta LOVE the VS2005 color scheme), and it's VERY easy to extend.

As another quick example here's how you would translate the following code into LLBLGEN code. First, the SQL code...

select *
from Person
where
PersonUserName = username and
PersonPassword = password;

Now the LLBLGen code...

   
PersonCollection people = new PersonCollection( );
IPredicateExpression filter = new PredicateExpression( );
filter.Add(PredicateFactory.CompareValue(PersonFieldIndex.PersonUserName, ComparisonOperator.Equal, username));
filter.AddWithAnd(PredicateFactory.CompareValue(PersonFieldIndex.PersonPassword, ComparisonOperator.Equal, password));
people.GetMulti(filter);

Yes, joining is also BEYOND easy and, yes, it databinds to GridViews with no extra work. I use it all the time in my ObjectDataSources.

OK one last example... well two. This one should be the straw that breaks...something. Look at this ADO.NET code (I'll leave some of it out though)

sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = "insert into Customers (CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax )values(@CompanyName, @ContactName, @ContactTitle, @Address, @City, @Region, @PostalCode, @Country, @Phone, @Fax)";
sqlCommand.Parameters.AddWithValue("@CompanyName", companyName);
sqlCommand.Parameters.AddWithValue("@ContactName", contactName);
sqlCommand.Parameters.AddWithValue("@ContactTitle", contactTitle);
sqlCommand.Parameters.AddWithValue("@Address", address);
sqlCommand.Parameters.AddWithValue("@City", city);
sqlCommand.Parameters.AddWithValue("@Region", region);
sqlCommand.Parameters.AddWithValue("@PostalCode", postalCode);
sqlCommand.Parameters.AddWithValue("@Country", country);
sqlCommand.Parameters.AddWithValue("@Phone", phone);
sqlCommand.Parameters.AddWithValue("@Fax", fax);

sqlConnection.Open();

string id = (string)sqlCommand.ExecuteScalar();

sqlConnection.Close();

Some would say that it would not look so bad if the insert was in an SP. Um, ok...so you want to code in more than one place? No thank you. Also, what happens if there is no id to return? I've noticed that .NET 2.0 doesn't like that too much.

Now heres the LLBLGen code...

CustomersEntity customer = CustomersEntity( );
customer.CompanyName = companyName;
customer.ContactName = contactName;
customer.ContactTitle = contactTitle;
customer.Address = address;
customer.City = city;
customer.Region = region;
customer.PostalCode = postalCode;
customer.Country = country;
customer.Phone = phone;
customer.Fax = fax;
customer.Save( );

string id = customer.CustomerId;

Yeah...wow. Not only that, but in the SQL code you also have to do all that ADO.NET stuff. Not with LLBLGen, it's all in one!

I've been using LLBLGen for almost a year now and I have to say that my productivity has SOARED because of it. LLBLGen + .NET 2.0 + Firefox is a smart, er..., GENIUS match that should not be ignored, but rather ran towards!

To get a 30-day trial copy of LLBLGen follow the below link. I'm sure you will love it and for only $300, your manager will as well.

(2 Comments)

C# 2.0 Self-Test

Thursday, December 1, 2005

In the .NET course I'm teaching (".NET Complete") I gave a little project to the class, of which all of them are new to OO design, C#, .NET, and all the related items. The project requirement was for them to study the example and see what it does. The point of the project was to allow them to test their knowledge of C# syntax, collections, generics, and nullable types

It's almost as useless as "Hello World". Or,rather, hello world is almost as useless as this.

You simply type in string and it tokenized it into characters...but they didn't know that.  Anyhow here you go...

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace CodeExamples
{
    class Program
    {
        class Storage<T> where T : ICollection<Char>, new( )
        {
            private Dictionary<String, T> list = new Dictionary<String, T>( );

            public void ShowLines( ){
                Int32? i;
                foreach(KeyValuePair<String, T> collection in list) {
                    i = null;
                    if(collection.Key.Length > 2) {
                        i = collection.Key.Length;
                    }

                    Console.Write((i ?? -1) + " : " + collection.Key + " : ");
                    foreach(Char thing in collection.Value) {
                        Console.Write(thing);
                    }


                    Console.WriteLine();
                }
            }

            public void Save(String text) {
                T parts = new T( );
                foreach(Char c in text.ToCharArray( )) {
                    parts.Add(c);
                }

                if(!list.ContainsKey(text)) {
                    list.Add(text, parts);
                }
            }
        }

        static void Main(String[] args) {
            Storage<Collection<Char>> storage = new Storage<Collection<Char>>( );

            Boolean done = false;

            while(!done) {
                String text = Console.ReadLine( );

                if(text == "end") {
                    done = true;
                    continue;
                }

                storage.Save(text);
            }

            storage.ShowLines( );
            Console.ReadLine( );
        }
    }
}

(2 Comments)

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.5 License.

Powered by the Minima Blog Engine 3.1 and Squid Micro-Blogging Library.

Built on Themelia Framework 2.0

Developed using NetFXHarmonics DevServer 1.1.

(all of which are NetFXHarmonics products created by David Betz)

Mini-icons are part of the Silk Icons set of icons at famfamfam.com