Why Is There a Default Instance of Every Form in Vb.Net But Not in C#

Why is there a default instance of every form in VB.Net but not in C#?

This was added back to the language in the version of VB.NET that came with VS2005. By popular demand, VB6 programmers had a hard time with seeing the difference between a type and a reference to an object of that type. Form1 vs frm in your snippet. There's history for that, VB didn't get classes until VB4 while forms go all the way back to VB1. This is otherwise quite crippling to the programmer's mind, understanding that difference is very important to get a shot at writing effective object oriented code. A big part of the reason that C# doesn't have this.

You can get this back in C# as well, albeit that it won't be quite so clean because C# doesn't allow adding properties and methods to the global namespace like VB.NET does. You can add a bit of glue to your form code, like this:

public partial class Form2 : Form {
[ThreadStatic] private static Form2 instance;

public Form2() {
InitializeComponent();
instance = this;
}

public static Form2 Instance {
get {
if (instance == null) {
instance = new Form2();
instance.FormClosed += delegate { instance = null; };
}
return instance;
}
}
}

You can now use Form2.Instance in your code, just like you could use Form2 in VB.NET. The code in the if statement of the property getter should be moved into its own private method to make it efficient, I left it this way for clarity.

Incidentally, the [ThreadStatic] attribute in that snippet is what has made many VB.NET programmers give up threading in utter despair. A problem when the abstraction is leaky. You are really better off not doing this at all.

VB.Net default form instance

Contrary to popular belief, the generation of Default Instances in a WinForm application is not a mandatory feature of Visual Basic.

From the Visual Basic Language Specification Version 11 (emphasis added) :

11.6.2 Default Instances In some situations, classes derived from a common base class usually or always have only a single instance. For
example, most windows shown in a user interface only ever have one
instance showing on the screen at any time. To simplify working with
these types of classes, Visual Basic can automatically generate
default instances of the classes that provide a single, easily
referenced instance for each class.

The problem is that I know of no documentation that tells you how to enable/disable their creation. It is known that this feature is part of the Application Framework that can be enabled/disabled in the "Application Tab" of the project's properties pages. However, disabling the Application Framework does not disable the default instance generation.

If instead selecting the "Windows Forms App" template when creating a project, you select the "Empty Project" template and proceed to add a form, you can create a WinForm project in which the "Enable application framework" checkbox is grayed out and not selectable. You will also find that you can not use default form instances. From this, you can deduce that this feature can be configured via "*.vbproj" file.

The controlling item is the <MyType> tag. The possible values for this property are:

  • Empty - application framework unavailable
  • Console
  • WindowsForms - application framework enabled
  • WindowsFormsWithCustomSubMain - application framework disabled
  • Windows - Class Library
  • WebControl - library

So if you want to convert an existing project to one that does not support default instances, you can edit the "*.vbproj" file and change the <MyType> property to Empty.

Be aware that doing this will also eliminate other features of the application framework such as My.Computer and My.User, but you could always implement those features yourself such is described in How to: Use the My Namespace (C# Programming Guide).

Why does this code sample work as intended in VB.NET but not in C#?

Your VB code is leveraging the feature of a default form instance.

(In VB.NET) Behind the scenes each of the Form classes is given a static variable of the same type as the form itself, and when a new form is created it sets itself as that static variable's value. That variable is also the default static property of that type (another feature that VB has that C# does not) which is why you can use the type name to directly access this property. You can see this related question for a bit of history as to why this feature still exists in VB, despite the fact that it doesn't strictly make sense any more.

There are ways of mostly replicating this behavior in C#, creating the static property yourself and setting/clearing it manually, but I strongly discourage you from doing so. This general concept is rather poor practice, which is why this feature was intentionally omitted in C#.

There isn't conceptually just a single instance of forms, even if some of the forms that you use my happen to only exist once.

A more preferred practice would be to create an event in your second form that the first form subscribes to. (Or uses an existing event, if appropriate). In this case you want to have the parent form have Enabled set to false whenever the child form sets it's Enabled to true, you can do this through the use of an existing event.

When you create your child form, from within the parent, just use the EnableChanged event to change the parent's property based on the child's actions:

Form2 child = new Form2();
child.EnabledChanged += (s, args) => Enabled = !child.Enabled;

Then the child form never needs to know anything about it's parent. This is fantastic from a design perspective. You reduce coupling, and improve modularity. The developer of the child form doesn't need to know anything about the parent form or what it needs to do. The child form just needs to know how anyone might want to use it and provide the needed functionality.

Form cannot refer to itself through its default instance on shared call

Creating a variable alias that has the same name as the type of the Form class is without a doubt the single most disastrous VB.NET problem. But it was necessary to give VB6 developers a fighting chance to move to VB.NET.

The workaround is to stop trying to be explicit about what method you want to call. This compiles fine and is unambiguous, at least in your snippet:

  Private Sub AAA()
AAA(Nothing) '' fine
End Sub

If that really, really hurts then simply swapping the two methods removes the ambiguity:

Private Shared Sub AAA(str As String)
End Sub

Private Sub AAA()
Form1.AAA(Nothing) '' fine
End Sub

Class appears to be used without an instance. It is possible? VB.net

I am assuming that you are not aware of Default Form Instance in VB.NET and hence the surprise. Its a common problem since this is missing in C#.

For winforms application in VB.NET, each form has a default instance and can be referred to simply by its form name (class name). You can ofcourse create your own instances like any other class and choose not to use the default instance.

This feature is particularly useful for legacy applications that have been migrated from VB6 to VB.NET since default form instance was a norm in VB6.

You can read more about Default Form Instances here:

https://msdn.microsoft.com/en-us/library/ms233839.aspx

And

https://msdn.microsoft.com/en-us/library/aa289529(v=vs.71).aspx

Objects implicitly instantiated in vb.net?

Yes that is legacy behavior. Classes did not show up in VB until v4, before that Form1.Show was The Way to show forms. In order to keep previous code compatible (VB3 was also very popular), the old method was maintained.

It is still supported in .NET as a legal means to show forms. Initially, this was added to make it easy to migrate VB6 code to VB.NET. But is also there to make it easy to get something running in VB - MS refers to it as functionality at your fingertips and similar phrases.

Basically, it provides the tinkerer an easy way to program without understanding Objects and OOP. Imagine the questions we would have here if Form1.Show threw an error.

Explicit instancing is the better method because it is object oriented and makes it less likely your code will reference - or create - a new Form2 when you actually wanted to use an existing instance.

VB.Net form non-shared methods referenced as if they were shared?

VB.NET has the (very nice) feature of keeping a collection of all forms as properties under the My.Forms object. The objects there are instantiated when you first access them. In this way, you get a default instance of each form that you can refer to.

On the not so nice side, VB insists on importing the My.Forms object’s properties globally, and there’s nothing you can do to change that.

In other words, the class name of any form in your application doubles as a global instance of that form.



Related Topics



Leave a reply



Submit