Get Help:Ask a Question in our Forums|Report a Bug|More Help Resources
Last post Nov 30, 2007 03:24 PM by Svante
Nov 07, 2007 08:14 PM|LINK
I'm trying to create custom datatypes in C# that mimic primitive data types, similar to the way TYPEDEF works in C++. Microsoft left this
feature out of the .Net framework (along with multiple inheritance and others), and I've been looking for ways around it.
Here are the two answers I keep running across in the forums I've seen:
1. The 'using' statement. In any class, I could simply say... using intResourceID = int;
I can't use it because: This simply aliases one type to another. The integer isn't really strongly typed. On top of that, I'd
have to cut and paste the code in too many places for this to actually be useful.
2. Wrapper classes. Basically, I could create my own "ResourceID_Int" class, which would contain an integer.
I can't use it because: This is re-inventing the wheel. Doing this for all the data types I'd need would defeat the purpose of trying to make
this solution easy. Also, I'd have to inherit and implement interfaces and classes to be sure that "FrederickInt" behaves exactly like an
integer, particularly if other developers try to inherit from it.
My question to this forum: What is the best way to create custom datatypes in C#?
Here are the two solutions I have been looking at:
- Using LinFU (from www.codeproject.com)
- Creating a Visual C++.Net project to include in a solution with several of my C# projects. My C# project could simply reference the C++
project that had my TYPEDEF-created custom data types. However, I am having problems making a C# project see my custom data types in C++.
Anything any of you have to contribute would be appreciated. Thank you.
Nov 08, 2007 07:07 AM|LINK
Native datatypes in c# are just sealed structs.
Nov 08, 2007 12:47 PM|LINK
Yes, they're sealed structs. You can't inherit from structs. You'd also have to implement all of the methods associated with, say, a String. That's a lot of methods to implement, and there has to be an easier way.
Nov 08, 2007 02:08 PM|LINK
Unfortunately there is no real easy way to extend a primitive type or a sealed class. However, C# 3.0, which will be released soon, supported "extension methods". This blog post explains them a bit in detail:
Nov 11, 2007 02:51 AM|LINK
Rockford Lhotka build a SmartDate struct that extends the DateTime class to support null dates among other features. His free, open source CSLA framework (which includes SmartDate) is available at www.lhotka.net. If you like it, check out the CSLA Contrib
library because I added half-a-dozen others supporting different datatypes.
Forgot to add that you might use that as a starting point.
Nov 20, 2007 03:00 PM|LINK
From what I'm seeing, there isn't a way to extend primitive types and sealed classes. I suppose that spelling out what I'm trying to do in detail would help me find a way around this.
I'm trying to make two custom types. "ResourceId" inherits from an integer, while "FredString" inherits from a string. A string is a sealed class, while an int is a primitive type.
The other path I could travel is using a C++.Net TYPEDEF. I could integrate the C++ project with the type definition into a solution with other C# projects and add a references to the C++ project containing the type definitions. The only problem is making
those other C# projects see the type definitions themselves. Because of the CLR, all of the .Net languages should be able to talk to each other regardless of language. Trying to make those C# projects see a C++ typedef didn't work when I tried it before.
Did I miss something? Again, anything any of you have to contribute would be appreciated.
Nov 20, 2007 04:38 PM|LINK
extend primitive types and sealed classes
Although it may feel counter-intuitive, and a bit bothersome coming from C++, the way to do this is to use composition not inheritance. Yes, I know it can be done with inheritance in other languages, but it's often not a good idea there either.
So, to make your FredString, you declare the class, and then just keep a private System.String in there and wrap it with whatever functionality you need.
No, you can't then pass around a FredString as if it was a string - but you can provide an explicit cast to make it ease to use as a string anyway, and you can and should override the ToString() method. The alternative is to make a static class that gives
you the behavior you want with the string. Remember that a string is, and must, be immutable for anything in .NET to work - so there's not that much you can do in a derived string class that can't be done with either of these ways anyway.
Especially if it's extending the string type you want, good oo practice does dictate that you should 'favor composition over inheritance'. C# is just giving you a helping hand there :-).
The same arguments pretty much apply to your integer variant, ResourceId.
Nov 20, 2007 06:07 PM|LINK
Thanks a lot, Svante. Your help is appreciated.
Still, I can't use a wrappper class. (I tried earlier in November.) I promise I'm not trying to be a bother to you or anyone else.
Basically, I'm trying to implement this at my job. If I create a "FredString" or "ResourceId" using wrapper classes, that class would have to be referenced in every component of every web application my company has written over the past year and a half.
Since there are a countless number of them, implementing custom data types with wrapper classes might not be a good idea. Some of those applications can't be touched, because changing one might break other working applications. I should have mentioned this
In other words: Are there ways to implement "FredString" and "ResourceId" as custom data types without using wrapper classes?
Nov 20, 2007 06:21 PM|LINK
I can't use a wrappper class.
I'm afraid your options are fairly limited. You cannot derive from 'System.Int32' or 'System.String' (for different reasons, but the result is the same).
Can you elaborate on just how FredString and ResourceId differs in behavior from 'System.String' and 'System.Int32' respectively, there might be some other way around it? Just what is it you're trying to achieve?
In your earlier posts you did note that you're aware of the 'using' alias mechanism, which is fairly equivalent to C/C++ 'typedef'. You did confuse me a bit with using both the capitalized TYPEDEF and lowercase 'typedef'. Do you mean a COM+ type definition
Correct me if I'm wrong, but I'm getting the impression that you perhaps do not want to modify the behavior at all, you just want to ensure that the 'ResourceId' integer is always just that - a ResourceId, not just any integer. I'm afraid a wrapper struct
and a wrapper class (for the FredString) is just about your only options.
Your concern that you'd have to change in a zillion places is a natural consequence if the above is the desired effect - that's after all what you want then. To ensure that it's always a 'ResourceId' and a 'FredString' respectively. You can't both have that
cake and eat it too.
As for legacy code you can't change, you'll just have to validate and convert at the boundaries.
Sorry, unless you can give some more background I can't think of much more.