Click here to Skip to main content
6,596,602 members and growing! (20,546 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate License: The Code Project Open License (CPOL)

How to expand .NET structs and sealed classes in C#

By Kaveh Shahbazian

A way for expanding sealed data structures in .NET
C# 1.0, Windows, .NET 1.0VS2005, Dev
Posted:1 Aug 2006
Views:13,694
Bookmarked:11 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
7 votes for this article.
Popularity: 2.48 Rating: 2.94 out of 5
1 vote, 14.3%
1
2 votes, 28.6%
2

3
1 vote, 14.3%
4
3 votes, 42.9%
5

Introduction

Sometimes it is required to add some functionality to existing data structures. The OOP school's way for this is to use inheritance. In situations where we consume interfaces instead of class or structure types we can extend the interface easily. In some languages like Ruby data structures are never sealed. So we can add extra abilities of our objects to the processing workflow of the running engine of the language. However, if the data structures are sealed then there could be no way to do this.

Here we'll see a way to convert two types implicitly that 'simulates' inheritance and when needed our type will be cast internally by the CLR.

Background

When I was studying a few Ruby code snippets I encountered this idea and decided to implementing it in C#. In some scenarios this is very handy. Ruby programmers use this feature in their daily developments. But there is a bit of caution here: this method can be Aggregation or a Composition, and if you are going to extend a complex sealed type in .NET, you must be aware of how it is disposed (Implementing of IDisposable is a formal way for doing this). Because the wrapped type does not release it's captured resources, there may be some conflicts in execution path. So the finalization process must takes place properly.

Overall Process

For this we need to construct some facilities in our data structure that enables the CLR to 'infer' our target type from the context.
  1. Implicit overloaded operators for conversion

    Here we'll try to expand string class so this operations will be:

            public static implicit operator string(String V)
            {
                return V.mval;
            }
            public static implicit operator String(string n)
            {
                return new String(n);
            }
    //REQUIRED BECAUSE OF CONVERSION OPERATORS public override bool Equals(object obj) { return this.mval == (string)obj; } public override int GetHashCode() { return this.mval.GetHashCode(); }
    As you can see by browsing the provided code 'mval' is the internal place for
    keeping the object of target type which is 'string'. 'String' is our new type, and 'string' is the .NET standard type for the strings.

    In addition we have overloaded two other methods : Equals and GetHashCode. These implementations are needed by the CLR for performing the conversion.
     
  2. Providing implementations of necessary unary and binary operations.

    Here the only operation that is defined in .NET framework for strings in '+' which makes a new string of it's operands. Of course we can overload other operations in addition to '+' for our purpose.
     
  3. Providing implementation of comparison operators.

    This is in fact same as previous step and the separation of conceptual paragraph is only an emphasis on it's importance that needs more care.

After this we have done and we have a new type that is equivalent to standard string. We can use it to provide a new type 'email' that is a string with a special format or in any sort of data that will be presented in a formatted string.

Using the code

Let see through the code some practical points. This is main method that performs a simple test :
static void Main (string[] args)
{
    UpperCaseString ucs = "this Is A teST TeXt.";
    Console.WriteLine (ucs);
    Console.WriteLine (ucs << 8);
    string newString = ucs << 8 >> 1;
    Console.WriteLine (newString);
    //

    Console.WriteLine ("Press any key to continue ...");
    Console.ReadKey ();
}

UpperCaseString is an always upper case string class. As you see the instance of UpperCaseString has been initialized by an ordinary assignment. Then it is consumed by the WriteLine method of the Console class to print its value. There is no explicit conversion needed here.

There are new overloaded operators there : '>>' and '<<'. The first one shifts the string n characters to right and '<<' shifts the string n characters to left. Again there no necessary instructions for constructing a new instance of System.String named here newString. The result of '>>' and '<<' operations are automatically converted to the proper type (here System.String).

This was a little example of using this feature to attach additional functionalities and properties to existing sealed types. You can use the definition of UpperCaseString as a template for providing your specialized types. In addition you may want to provide some generic tools for performing needed applications.

Points of Interest

It is interesting how can this option affects current implementation scenarios on the .NET plateform. We can name some of them by re-implementing required features in new way. Maybe some sort of parsing texts and file processing or some of GUI data propagation and data gathering and so on. But the more interesting thing would be a case that is nicely fit this and this suited nicely to overcome the problem. Do you know one?

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Kaveh Shahbazian


Member
A .NET Developer came from a 'C' and 'C++' background with some experiences in low level programming. In last 2 years I have performed various works in ASP.NET 2.0, .NET compact framework and other .NET things.
I am looking forward for functional programming to be mainstream (Lisp (Scheme), F#, Erlang and Haskell (Clean)). There are two path there I love them both: Lisp path (Power of macros with Scheme, ...) and ML path(Power of ADT and patterns with F#, Haskell, ...) and there are some middle ground too (Nemerle, Scala).
Occupation: Web Developer
Location: Iran, Islamic Republic Of Iran, Islamic Republic Of

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
Question.NET 2.0? Pinmemberhockbock17:07 23 Oct '06  
AnswerRe: .NET 2.0? PinmemberKaveh Shahbazian4:10 28 Oct '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 1 Aug 2006
Editor: Chris Maunder
Copyright 2006 by Kaveh Shahbazian
Everything else Copyright © CodeProject, 1999-2009
Web09 | Advertise on the Code Project