.NET     Console.WriteLine( "All Things .NET" );
.NET Nerd Blog Home
2.28.2002

 

Fun with virtual, override, new, and base classes



I was asked last week: in c#, if I'm in a given derived class instance method, how would I call down to a method in the 2nd generation child of the class that I'm in?

class A { foo() {...} }
class B : A { foo() { ... } }
class C : B { foo() { <call down to A::foo here> } }


The c# keyword "base" allows you to reference anything in your base class (ctor, method, field, property, etc), but if you want to SKIP a base class in the derivation chain, you are out of luck --- as far as the base keyword is concerned.

base.base.Foo() doesn't work.



Turns out the answer is fairly simple - just have to go back to our c++ roots with casting.

((A)base).Foo() works just fine.



virtual, override, new

I know the rest of this is documented in and around the .NET community, but I like to have it here in once place for me to remember.

Given the following code, we will play with the 3 magical keywords and see what effect they have on the outcome of the program.


class BaseClass {
public void Identify() { Console.WriteLine("BaseClass::Identify"); }
}
class DerivedClass:BaseClass {
public void Identify() { Console.WriteLine("DerivedClass::Identify"); }

static void Main() {
DerivedClass test = new DerivedClass();
BaseClass b = test;
b.Identify();
}
}


--- new ---

This code as is generates a warning - keyword new is required because it hides inherited member.
The program will still run with these warnings, and b.Identify() will call the base class implementation (static binding at compile time). Adding "new" keyword gets rid of compiler warning, and the program results are the same.



--- virtual / override ---

Once we add the "virtual" keyword to the base class, we have a similar compile warning - ... hides inherited member. To make it override the implementation, add the override keyword, otherwise add the new keyword. Again, this program still runs despite this warning, but you get static compile time binding, which calls the base class function.
Add override to the derived method and all our problems are solved !!




2.26.2002

 

Notes about Remoting and Events



I'm just getting started with remoting, checking out the Chat sample with the SDK. Shows simple chat clients that connect to chat server which simply broadcasts the incoming chats from all clients. Here are a few thoughts about the remoting infrastructure:

The Server
Amazed that the server process doesn't really have any code in it!! Just calls RemotingConfiguration.Configure("ChatCentral.exe.config"); then sits at a Console.ReadLine waiting for end of applicaiton. All configuration of the object that will run in the server process is contained in the config file.

wellknown
mode="Singleton"
type="ChatCoordinator, ChatCoordinator"
objectUri="Chat"

The above xml describes that the object called ChatCoordinator (actually defined in a separate c# class library file) will be instantiated upon first client method invocation (docs say this, not during the client call to "new") and be a singleton object -- all clients will get a reference to the same object.


channels
channel
ref="http"
port="8080"

This says that the server object will receive incoming calls on http port 8080. netstat -an shows that this port is open and listening right after the call to RemotingConfiguration.Configure( )

The Client
Client code is also pretty basic. The client creates a new object that is configured to run on the server. After the call to RemotingConfiguration.Configure("ChatClient.exe.config"); the runtime now knows that creations of the ChatCoordinator object are now to be remoted to the given URI. The callbacks must have their own channel - in this case we specify 0 to let the system choose a port.

wellknown
type="ChatCoordinator, ChatCoordinator"
url="http://localhost:8080/Chat"

channel
ref="http"
port="0"


The standard event infrastructure sets up the callbacks from the server to the client when there is a new chat message. The chat client object creates a delegate and assigns it to the public event in the ChatCoordinator object.

Interesting notes:

  • SubmitEventArgs derives from EventArgs and is used to pass custom data to event handlers. Must be serializable for remoting.
  • ChatClient must derive from MarshalByRefObject, so the delegate to call back on can be passed out of the AppDomain. Get a SerializationException if not.
  • If client connects to the wrong port or wrong URL, you get System.Net.WebException "unable to connect to remote server"


2.25.2002

 

The Saga of Globalization



After a talk by Michele Leroux Bustamante at the SD .NET user group meeting last month, I was inspired to try ou the G18N and I18N functionality. In .NET WinForms, globalization of controls on the form are as easy as setting Localizable property to TRUE, then setting the Language property for each set of controls. The IDE automagically creates the appropriate .resx files (containing xml elements of our properties such as color, location, text, etc) for us, and when building, creates the projectName.resources.dll in the appropriate sub directory.

I wanted to go one step further and play around with string resources. The easiest way to accomplish this is with a text file of name-value pairs of identifiers and strings. This works great as a stand-alone exercise, but now I can't get the string resources to load with the controls/layout resources created by the compiler.

Using the IDE, you can add an "embedded resource file", which gives you the xml-based .resx file, but it doesn't seem to be localizable. So I went about it the manual way --- remember, you always have the command line.


  • created (notepad) mystrings.es.txt
  • resgen mystrings.es.txt mystrings.es.resources
  • build the project with IDE. this creates the blah.xxx.reources files for each language selected when laying out the winform
  • al /out:.\bin\debug\es\globalize.resources.dll /c:es /embed: .\obj\debug\globalize.form1.es.resources /embed:mystrings.es.resources


TADA! The last step in list above MERGES the strings resources with the IDE-created form resources for a given language (es [spanish] in this case).

Finally, in the code, load the strings like this:

Thread.CurrentThread.CurrentUICulture = new CultureInfo( "es" );
ResourceManager rm = new ResourceManager( "mystrings", GetType().Module.Assembly );
MessageBox.Show( rm.GetString( "Greeting", new CultureInfo( "es" ) ) );


Since the IDE doesn't seem to offer this as a built-in feature, it's begging for a "custom build step". According to a quick search on discuss.develop.com however, custom build steps are not supported in VS7 for VB or C#. An MS source said that you have to write a "plug-in" and talk to the environment through automation to accomplish this. Others pointed out that you can add a VC++ utility project dependency to the solution to accomplish the custom steps.



I owe a BIG THANK YOU to Michele Leroux Bustamante for her help on this topic. Together with her talk at the San Diego .NET User Group Meeting, and putting up with my email questions, we were able to get somewhere on this issue.

p.s. Some notes about this topic in ASP.NET (from DevX .NET zone)
Browser sends user culture preferences in HTTP headers. User sets this up in Tools | Options, Languages.
Usually detect settings in Application_BeginRequest

String[] prefs = HttpContext.Current.Request.UserLanguages;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture( culturePref );
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

Dynamically display images from different cultures.
Store images in subdirs based on their culture (ex: appname/images/fr-FR/image.gif )
To dynamically create these at runtime:

  • create server control containing HTML <img> tag
  • Create public property (something like URL) that you can get/set at runtime
  • Override the CreateChildControls method and construct the HREF attribute dynamically


protected override void CreateChildControls()
{
CultureInfo culture =
Thread.CurrentThread.CurrentCulture;
Image flag = new Image();
flag.ImageUrl = "images/" + culture.Name +
"/" + imageName;
flag.Width = imageWidth;
flag.Height = imageHeight;
Controls.Add(flag);
}




 

Run WinForms app from network



Simple method
Make web page with a link to your EXE. When clicked, runtime will automatically download the exe to the download cache and run from there. Supporting assemblies are downloaded when needed.
Next time the user clicks that same link, runtime does version checking and downloads necessary updates. Runs the app
from the download cache.

Cool method
Write small "stub" exe, that just does a Assembly.LoadFrom( URL ), then run it.
This will similarly get downloaded to download cache and check versions, etc.


2.01.2002

 
It all started with Guerilla.NET at Developmentor.
These guys showed me the light, and I was off to learn all about .NET.
Some links to keep track of:
John Lam's blog - a lot about CLR internals
Chris Sells Spout





Powered by Blogger