| Rory's profiledotNotedPhotosBlogLists | Help |
|
|
September 05 InternalsVisibleTo needs the whole public key in CLR v2.0 RTMHopefully, this post will help the search engines to set the record straight about the InternalsVisibleTo attribute for creating friend assemblies. A number of notable .Net voices (Oliver, Juval, James World) used this attribute in pre-RTM code, when the public key token was used, but Microsoft changed it in the release. In one post in particular, a commenter, Neil, was trying to say that PublicKeyToken isn't available for InternalsVisibleTo - only PublicKey is. C# MVP Oliver Sturm counters by explaining that it seems pointless to use the whole public key, since it is so much longer to copy than the public key token. While this is true, he apparently was unaware of the change when he wrote this. It was changed in .Net 2.0 RTM. MSDN, after remaining inaccurate after release for some 9 months, now shows the correct syntax. Update: David Kean also points this change out, and notes that it was changed in RC1, which if I recall correctly was released right after the PDC and right before the November RTM. David also has a nifty utility which generates the otherwise onerous attribute for you. Nice. April 27 OdbcFactory.Instance.CreateDataSourceEnumerator does nothingThis method sounds cool - like it would enumerate ODBC sources on a machine. However, it's not overridden from its base class, DbProviderFactory, which is implemented like so: public virtual DbDataSourceEnumerator CreateDataSourceEnumerator()
{
return null;
}
April 18 How to return an empty IEnumerable using yield?UPDATE: IEnumerable<Foo> GetFooItems()
{
yield break;
}
...is what I want.
Given a method that returns an IEnumerable, you can use the C# 2.0 "yield" statement to return the next item in the enumeration. What if you want to return an empty enumeration? The only way I've found to do this is the following: if (false)
yield return null;
Any other ideas? January 26 What appear to be, by all observable accounts, hacks in the v2.0 BCLI found this while reflectoring. It appears that certain generic types are preloaded in order to prime the JIT compiler, and reduce type allocation (setting up MethodTables and EEClasses) latency. A reasonable thing to do, and probably testing of the framework found unsatisfactory results, so hacks were inserted, and clearly labeled. I wonder if a subsequent service pack will eliminate these? November 28 Getting more than 1000 results from a DirectorySearcher queryOk, this isn't exactly clear. Need to make a note of this so I don't forget it. The DirectorySeacher only returns 1000 results when the defaults are used. This setting actually comes from an AD server, not the .Net stuff, or even the ADSI or LDAP protocol implementation which are under the covers. So, basically, it's as good as hard-coded. ADSI helps out here, and we can take advantage of it, by just setting the DirectorySearcher.PageSize to a number besides 0. I like to set it to the DirectorySearcher.SizeLimit default which is 1000 (actually, it's 0, but this means 1000). This actually makes ADSI make as many paged requests as needed to get the entire result set, not just the first SizeLimit records. The docs aren't terribly clear on this, and I try to make repeated requests to the server until the resulting SearchResultsCollection's Count property is less than the searcher's PageSize property... which doesn't work since ADSI has done this bit for me and now I'm sitting with all the results in the collection. Here's how to get all the users (with a few properties) in the domain [in IronPython]:
November 25 DirectoryInfo and Path rely on ancient technology - the sad story of MAX_PATHNTFS is a very robust and well architected file system. I like it. I've looked at others, like WinFS (not really a core FS, just a layer on NTFS... but good Oddly, this is hardcoded into two places - Win32 and the CRT:
However, help is at hand... From the MSDN docs:
But, try creating a DirectoryInfo prefixed with \\?\ ... you'll throw an exception since it contains an invalid path char (?). Too bad, since people are finally getting the hang of long file names... one more legacy to detract from the shininess of Vista. I've opened a Connect issue... if you run into this, be sure to vote for it. June 07 Code Generation in DataSet designer doesn't change project namespace workaround.Net adds a bunch of useful features, no doubt. Sometimes they trip over themselves though.
Take, for example, the "global" namepace. This allows you to create "namespaceless" code and probably has some benefits, though I wonder what they are (perhaps they aren't necessarily for C#).
When you create an ASP.Net project, your code is placed in the "global" namespace. This is fine, because mostly you don't care. However, it can cause problems. For instance, when you have an ASP.Net page called "Login", the generated class becomes "Login". In the code-gen which results in the classes that imlement your ASPX pages, there is no way to distinguish the Login class with the Login control which also exists in the global namespace. You get an error during runtime - "CS0030: Cannot convert type 'ASP.login_aspx' to 'System.Web.UI.WebControls.Login'" and it shows the invalid cast which was generated: "((Login)(this)).AppRelativeVirtualPath = "~/Login.aspx";".
One of the ways you get around this is giving your code a namespace, which, in my estimation is a good thing to do to begin with - otherwise you will get runtime issues like these. And runtime issues are never good, especially when you can push those issues into designtime. This is where the problem noted in the title comes in. The DataSet designer isn't aware of the namespace you give your code. There is no way to change the namespace of the project like in 2003. This is a step backward, VS folks.
The only real way around this is to put the DataSet in a separate project. I ended up doing this. April 04 Paths in Asp.Net 2It's not immediately evident how to find where you are currently, in terms of the web site and server, in an Asp.Net app. MSDN comes to the rescue here, mostly, with a decoder ring page, but it's not easy to find itself.
Basically, the points are:
March 01 Don't ever do this bad thingThis is bad:
protected override void OnLoad( EventArgs e )
{ base.OnLoad(e); PubsDataSet.Instance.UpdateFailed += new UpdateFailedDelegate(Instance_UpdateFailed);}
As you can see, this is an override from an ASP.Net code behind class. Yep, the .Instance property is a Singleton. I knew it was a no-no to hook up an event listener to a static instance in an Asp.Net solution, because the resulting class which has the listener never gets GC'd, and you get memory leakage in a nasty way.
What's more, if you execute the code above, what happens is that all references to controls on the page return "null" since, due to the way that events are implemented as linked lists, the reference that you are looking at in the event handler is an old instance of the page, which should have been disposed, but isn't because you have a reference outstanding and the GC won't collect it.
However, knowing this didn't stop me from doing it in an example I'm cooking up for a course. This is why experience is valuable - you know when something is wrong because you've felt the pain of doing it wrong, which lends to a much more acute sense of what is right than just studying it. Knowing the symptoms from studying the above analysis earlier helped me kill this bug in under 30 minutes, but having the experience will prevent me from creating the bug.
Here is a good solution which makes use of an Anonymous method to handle the event callback. Notice how the handler is removed when the page is unloaded - this is key: private UpdateFailedDelegate updateFailed = delegate( object sender, UpdateFailedEventArgs e ){ EditErrorLabel.Visible = true;EditErrorLabel.Text = e.FailureReason.ToString(); }; protected override void OnLoad( EventArgs e ){ base.OnLoad(e); PubsDataSet.Instance.UpdateFailed += updateFailed;} protected override void OnUnload( EventArgs e ){ base.OnUnload(e); PubsDataSet.Instance.UpdateFailed -= updateFailed;}
February 24 Why C++ needs .H filesI never questioned why C++ needs .h files - I just accepted it. Definitions go into .h files, and code goes in .cpp or .c files. Strange, I know - me just accepting without questioning. Huh. I suppose it was the nice side effect of having the .h file be your API definition. But that's not really why it _has_ to have one. You need it because the C++ compiler is a clunky beast which only does a single pass through the code. Sure, there is some history for this, but there really isn't a tenable argument to be found why it should stay this way. I found all this out by trying to resolve a circular reference among objects which I am creating to wrap the Shapefile library by Frank Warmerdam. This post helped me unravel that issue, and deduct the real reason behind .h files. So basically, you can do this: In ShapeObject.h: // a "stub" definition for the related class which contains ShapeObject
ref class ShapeFile;
public ref class ShapeObject
{
private:
Boolean _isDisposed;
SHPObject* _internalHandle;
Int32 _index;
ShapeType _type;
// Now we don't get a compilation error here
ShapeFile^ _parentFile;
.
.
.
};
And in ShapeFile.h: #include "ShapeObject.h"
public ref class ShapeObjectsCollection : public System::Collections::Generic::List
{
public:
ShapeObjectsCollection() { }
};
public ref class ShapeFile
{
private:
ShapeObjectsCollection ^ _shapes;
.
.
.
};
The important thing is the stub declaration... since the C++ compiler only does one pass, it needs to be declared before hand... implementation can be done later, which is where the .h/.c[pp] split comes in.November 24 Generic funGenerics are really cool...
...
bummer - i thought i might have one of those "You're our lucky 1,000,000th person who said that winner!" banner descend from Javascript heaven.
Anyway I had a hard time using them vs. code-generation of collection classes since code gen had the advantage of non-generic _names_. But I just found out we can do this:
{ private string _roleName; public string RoleName{ get { return _roleName; }} } public sealed class RolesCollection : List<Role> { public Role this[string roleName]{ get{ foreach( Role r in this ) if( r.RoleName == roleName ) return r; return null; } } }
Now I can have my cake and eat it too. Yum.
-rory |
|
|