Armin said:
It works because there is never a keyword after the dot.
BTW, what do you think is the name of the field? Is it "[String]" or is it
"String"? I've looked at the IL code and it says:
.field public string String
So, the brackets are _only_ there for the compiler to be able to
distinguish between an identifier and a keyword in it's first, lexical,
compilation pass. The brackets don't belong to the identifier itself,
i.e. they are removed.
Correct. I appreciate taking it to a levels I can grasp.
Thanks Armin for being patience in my venture to understand VB.NET
semantics.
You see, this is important for a person like myself coming from a
C/C++ world where hungarian notations and lower/upper case matters. It
is fundamental in the readability and undertanding of APIs and
libraries. So not to argue, I have to have a small nit with you that
I do think its about code readability and developer semantics.
For example, when one sees an traditional WIN32 API function such as
BOOL xyz(LPCSTR a, LPVOID b)
you know right away that is a constant (byval) long pointer to a null
terminated string and a long pointer to a untyped variable. Like
wise, a Hungarian prefix is well understood by veteran C people.
But in regard to VB.NET brackets, this is common practice in C/C++
(and I guess C# too), where case is very important as you know:
TYPE_NAME type_name
ie.
HANDLE handle;
PHANDLE phandle;
From a code readability, when you see usages of type_name (lower
case), in the developers' or code readers' mind, they instantly know
it a variable of type TYPE_NAME
So I do think its about code readability and semantics because one
side would say that is a bad idea and another would say its not.
But if case is not a factor, then it can viewed as poor. The debates
on this has long been argued so lets do ourselves a favor and not
repeat what is better but I do wish to know what is recommended for
VB.NET.
In VB.NET, as you note, it doesn't matter because the compiler knows,
and also Intellisense seems to know too.
For example and this is more anyone and not you because you know this
, who is getting insights from this discussion, lets say I start
typing:
dim [wcseRverapi] as new WCServerAPI
then on the next line I type:
WCSERVERAPI.WildcatServerConnectLocal(0) [Enter]
the editor will automatically change that to:
wcserRerapi.WildcatServerConnectLocal(0)
which is great because IntelliSense is HELPING the coder to understand
what is being used.
But to me, if I used a bracket, I would continue to refer to it for
readability from anywhere and not just the VS editor
[wcserverapi].WildcatServerConnectLocal(0)
Yes, its both the same here from the compiler standpoint, I see that,
but it is about code semantics and readability. Casing is VB/VB.NET is
irrelevant so things like this make sense.
Ironically, this is almost related to something I have to work out
very soon during my final cleanup of my new .NET suite of classes.
I drafted a post to get insights from people, but I still needed to
learn more. Basically, the organization of my assemblies, classes and
namespaces.
This all started with a 3rd party VB developer who took our VB6 .BAS
modules,
WCTYPES.BAS - Type structures, constants, etc
WCSERVER.BAS - declare imports for SDK functions)
WCVB.BAS - declare imports for helper WCVB.DLL for variants
and converted to .NET marshalling and merged it all into one module
namespace WCServerAPI in a file called WcServerAPI.VB. The file was
part of his project examples.
So using this module as a basis, I began my VB.NET venture and created
a project called wildcat.net.server, added the wcserverAPI.VB to the
project and changed the line:
Module WcServerAPI ==> public class WcServerAPI
compiled and viola.
Then I began to do the following which you can then see how some of my
forum post related to my tasks:
- see how to break it up, I immediately thought of "include"
(remember the include discussion? <g>) I see where Partial
Classes could help, but after exploring that, it might be
better to keep some things separate.
- Added Events to wrap the callbacks (remember that thread?)
- Added helper classes that wrap functionality
Basically overall, I started to explore and I am having a blast with
the VB.NET
,
- what abstract classes I needed,
- Grasping memory management, disposal, can you trust GC?,
- Understanding "Self" or "this" ideas in classes (ME?),
- Where recursion is needed, and if this is good or bad in VB.NET
- where interfaces would apply for virtual I/O designs,
- where nested classes/structure can be used,
- where partial classes can be used,
- where Generic Classes and functions can help,
- how to leverage important ideas like
- operators
- properties
- default properties
- inherit type conversions (including XML)
- enumerators,
- etc.
One of the ways I learn is to RE-DO work I did in other languages. So
if already have something close to it in C/C++, rather than compile
it as C++/CLR (for now as I learn), I will seen how its done in VB.NET
or C#.
Here is a good example, in our native C/C++ WIN32 SDK, we have a group
of RPC client/server traversal functions:
BOOL GetFirstUser(DWORD keynum, TUser &u, DWORD &tid);
BOOL GetLastUser(DWORD keynum, TUser &u, DWORD &tid);
BOOL GetNextUser(DWORD keynum, TUser &u, DWORD &tid);
BOOL GetPrevUser(DWORD keynum, TUser &u, DWORD &tid);
where keynum can be one of these:
const int UserIdKey = 0;
const int UserNameKey = 1;
const int UserLastNameKey = 2;
const int UserSecurityKey = 3;
const int UserLastCallKey = 4;
where TUser is (shorten)
typedef struct tagTUserInfo {
DWORD Id;
char Name[SIZE_USER_NAME];
char Title[SIZE_USER_TITLE];
} TUserInfo;
typedef struct tagTUser {
DWORD Status;
TUserInfo Info;
...
} TUser;
I wanted to highlight TUserInfo "nested" structure because it promotes
recursion concepts in serialization, type automation needs.
Now, in our framework, we have three main databases:
Users
Files
Messages
So there similar traversal functions, for example for Files:
BOOL GetFirstFileRec(DWORD keynum, TFileRecord &f, DWORD &tid);
BOOL GetLastFileRec(DWORD keynum, TFileRecord &f, DWORD &tid);
BOOL GetNextFileRec(DWORD keynum, TFileRecord &f, DWORD &tid);
BOOL GetPrevFileRec(DWORD keynum, TFileRecord &f, DWORD &tid);
As you can see, the power of .NET generic functions, classes, types
can really make this REALLY sweet to generalize a .NET SDK framework.
So I just began to explore generic types and when I couldn't get it
compiled right, I explored and saw mixed usages of brackets like OF T
or Of [T] etc, hence the post.
I think for the above, based on my knowledge thus far, it would be
begin with something like this (one way):
function GetFirst(Of T)(ByVal keynum as Uinteger, _
Of data as T, _
ByRef Tid as UInteger) as Boolean
function GetLast(Of T)(ByVal keynum as Uinteger, _
Of data as T, _
ByRef Tid as UInteger) as Boolean
function GetNext(Of T)(ByVal keynum as Uinteger, _
Of data as T, _
ByRef Tid as UInteger) as Boolean
function GetPrev(Of T)(ByVal keynum as Uinteger, _
Of data as T, _
ByRef Tid as UInteger) as Boolean
I think the implementation might be (for one)
function GetFirst(Of T)(ByVal keynum as Uinteger, _
Of data as T, _
ByRef Tid as UInteger) as Boolean
select case(TypeOf(Data))
case TUser : return GetFirstUser(keynum,data,tid)
case TFileRec : return GetFirstFileRec(keynum,data,tid)
end if
throw new Exception ("Unsupported type")
end function
Of course, a design with interfaces and delegates and emumerators is
probably be a very appropriate approach here, helping to remove parts
like typeof() select case.
So I'm learning the .NET semantics.
--