March 2004 - Posts
Using the Label class today, I noticed that if line breaks are added to the Text and AutoSize is set to true, the label will not resize vertically.
I took the time and wrote a little Label class that allows this sort of auto-sizing.
Feel free to check out the source and/or download it.
I've had a fellow team member who had the following error message raised when VS.NET 7.1 was trying to run the post-build event batch file:
'PostBuildEvent.bat' is not recognized as an internal or external command, operable program or batch file.
This has happened to several people before her.
I worked on this for a while and came to the conclusion that the answer is that your registry has a key named HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor which contains a string value named AutoRun.
This value indicates what any instance of cmd.exe should run in it at start. This value changed the current directory to the C: root.
I cleared the value and the problem was solved.
Taking advantage of my new-found knowledge, I placed "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat" as the value, so that any cmd.exe instance would have be a VS.NET instance.
After being a bit pissed off at Microsoft in my last post, I did a little thinking.
The .NET community is a living community. Not only is this community a great place to exchange ideas and thoughts, but it is a place where the guys at Microsoft finally get to hear you, respond and hopefully consider what you've said.
This 'power' that is given to us is usually used to complain. Complain about bugs, features, strategies, delays and whatever it is that we find ourselves annoyed at.
I have the same level of contact with my customers, if not a higher one. They use their contact with me to do about the same thing - complain.
I don't blame them. This sort of thing is acceptable.
What we mostly forget, however, is how our daily experiences would have been different if it weren't for this software.
So I would like to say these two words: Thank you.
Thank you to all the teams inside Microsoft who helped create this set of tools and languages.
Getting paid for it is not an excuse to not be shown some gratitude.
I'm still pissed about the delay, though.
One last thing - This is not kissing up to anyone. This is giving credit where credit is due. We as a society suck at it, so don't give me any self righteous crap.
So Microsoft decided to postpone Whidbey (and Yukon, but I don't really care about that) to Q1 2005.
I would like to just point out that Microsoft came out this small:
(The Hebrew speakers among my readers will understand the loose translation ;)
Anyway, Scott asks “Which single feature are you most waiting for in Whidbey”?
My answer is: Refactoring.
You could really use Generics, Anonymous Methods, Iterators, and all the rest when talking about new development, but right now, I'm no where near new projects. I need something here and now. Refactoring is the feature I could use the most right now.
The System.CodeDom.Compiler.CodeGenerator class has a private method called GenerateType which takes a type and generates its comments, members, etc.
The thing is, that you can't really determine the order in which the members will be generated.
This is quite annoying all by itself (you can't generate pre-processor directives wherever you want them), but acceptable, since there has to be some logic behind the intention of the programmer who wrote this method.
Before I used the Microsoft.CSharp.CSharpCodeGenerator class, which derives from it, I created a CodeDOM graph and wanted to use it.
The collection which holds all the members to be generated is of type System.CodeDom.CodeTypeMemberCollection which has index-specific methods such as Insert, IndexOf and an index-bound CopyTo.
My question is this:
Why create methods that would mislead programmers that don't want to dive into the code? If the index doesn't matter, why can I work with it?
And if your answer is "Because you might have other code generators that would want to generate members according to the index", why isn't there a single piece of documentation about the fact that indexes don't matter in the current generators?
Update: I just noticed that I talked about this, but haven't given the order in which members are written, so here it is:
- Type Comments
- Start of Type Declaration
- Code Snippets
- Type Initializer (Static Constructor)
- Instance Constructors
- Nested Types
- End of Type Declaration
I'd like to address several of the comments to my last post:
Maybe it's me, but I can't see the circumstances in which a user of your method would want to call Decide(sideA).
But it does make sense to me to allow one or both arguments to be null: the caller of your method may have object references and not know or care if they are null.
I'm sorry many people misunderstood my example, partially, I admit, because it wasn't that good.
Let's take another example: The ICodeGenerator.GenerateCodeFromCompileUnit Method
In this case, I have to send three parameters. The last one is of type CodeGeneratorOptions and can be null.
However, I would not have known this, have I not looked in the docs, would I?
This is one of the cases where an overload sans the last parameter would have been useful.
And no, default values are not the case either, using a Win32 example, CreateFile("test.txt") is not easier to read than CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); Forcing programmers spell out the options they want makes the code more readable, since you don't have to go through the docs to look up the defaults.
- Jerry Pisk
Jerry, I think you're getting this the other way around.
If you're sure you want to get things right, yes, you can use the second option. However, if you know that all you need is a file that would be created, always overriding and would have normal attributes, you would call the first version, since you can deduce these are the defaults for the operation or might even not care.
Besides, this would cause huge method calls in your code, thus making it less readable.
One last thing I wanted to reiterate was that this is not the case when dealing with unknown input. If I knew there were always two parameters retrieved from the user and sent directly to the method, I would go with the two parameters approach and be done with it.
However, what I was talking about referred to when you have other methods calling your method with their own data and logic. This is the case when you would want to do something like this.
A programmer, let's call him Jehosaphat, wrote a method.
This method was intended to decide in trials whether Side A was right or Side B of any given case.
public WinningSide Decide(Side sideA, Side sideB)
Pretty awesome, eh?
Anyway, Jehosaphat decided that he wanted to be able to use Decide even if only one of the sides was present at the time of the trial. What he did was check in the method's body whether sideA or sideB was null and returned a value accordingly.
He even wrote in the method's documentation that either side could be null. What a hard working lad.
I've come to see this sort of behavior especially in Ex-VB6 writers. This is wrong. If you are reading this, never do this sort of thing unless both parameters come from an uncontrolled source (such as user input).
What you should do is create an overload for the method such as this one:
public WinningSide Decide(Side presentSide)
So that the person reading it would know that they can use only one parameter as well as two. Better readability. Better maintainability.
The TypedDataSetGenerator class that is the working code behind the XSD/DataSet designer in Visual Studio.NET has an annoying little bug.
If you create, in the xsd file, a table called Data, the name of some of the classes might become ambiguous and a CS0146: Circular Base Class Definition compiler error will occur.
Here's another one for your unit tests. ;)