Is it possible for a public-facing property to return either a string OR a numeric w/o using 'Object'? - vb.net

So I've run into a case where I have a class that can store either a string or a numeric value, and I want a single property to return one or the other (it would be a failure for both to be set). I'm using a custom generic class to deal with the numerics (so I can use signed, unsigned, and nullables), and will be storing the string in a separate variable.
In theory, if overloading could be done based on the return type, I could do this quite easily. But .NET currently disallows this. So I am wondering if there is some other really-far-out-there trick (outside of MSIL generation via Reflection.Emit) that could accomplish the same thing.
I'm open to ideas via delegates, pointer dereferencing, generics, mystical rites, etc. Also interested in any thoughts or pros/cons of such possibilities as a learning tool. If using a standard Object is the only way to achieve what I want, then that's fine with me. But It's difficult to find the correct set of keywords to hunt down this kind of capability on Google, so I thought I'd ask here before I moved on to doing something else on the project.

I don't see how using anything other than Object would work, for a simple property. Imagine you're the caller - what would you expect the declared type of the property to be? What type of value would you try to assign the expression to?
If you really have to have a single property which can return various different types, Object sounds like the way to go.

You can have the public property as string and also return the number after converting it to string.
public string YourProperty
{
get {
if(somecondition)
return "some string";
else if(someothercondition)
return 1234.ToString();
}
}
while accessing your property you can use Convert.ToInt32().
Example:
public void YourMethod()
{
int a;
string str;
bool isNumber;
try
{
a = Convert.ToInt32(obj.YourProperty);
isNumber = true;
}
catch(FormatException e)
{
str = obj.YourProperty;
isNumber = false;
}
}
Though this is not a good way programming, but you will acheive your objective of using only one property for both string and number.

Related

Getter setter in C# VS2017

I've been starting to use VS2017 Community. This bugs me:
Below is normal getter setter from previous VS:
public string Name
{
get{ return _name;}
set{ _name = value;}
}
This is the new getter setter:
public string Name { get => _name; set => _name = value; }
Anyone can explain to me why the syntax is changed?
I wouldn't say they changed it, I would say they gave us some new syntax options. You can still use the "old" way of declaring getters and setters, but there is now also a more functional programming style of doing it as well. In C#6 Microsoft already introduced using expressions for getter only properties doing:
public int SomeProp => someMethod();
C#7 enhanced this support allowing it to be used for getters AND setters. One nice feature of this is with the new "throw expressions" feature which allows us to make some concise syntax. For example, before you had to do.
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (value == null)
throw new ArgumentNullException(nameof(Name));
_name = value;
}
}
We can now simplify this to:
private string _name;
public string Name {
get => _name;
set => _name = value ?? throw new ArgumentNullException(nameof(Name));
}
Granted, you could do the throw expression even without making the setter a lambda, but as you can see, for simple things, it makes the syntax very concise.
As with anything, use the syntax that makes the most sense to you and is most readable for the people who will be coding your application. Microsoft has been making a push to add more and more functional programming style features to C# and this is just another example of that. If you find it ugly/confusing/not needed, you can absolutely accomplish everything you need with the existing method. As another example, why do we have while and do while loops? I can honestly say I've used a do while loop maybe 5 times in my career. A while loop can do everything a do while can just with different syntax. However, there are sometimes where you realize that using a do while will make your code more readable, so why not use it if it makes things easier to follow?
The syntax hasn't changed: it has been improved. C# has been always backwards-compatible with syntax and grammar from previous versions.
Why property getters/setters can be implemented with lambda syntax (expression-bodied accessors)? Probably there's no scientific reason to do so, but there's a consensus about introducing useful functional programming constructs in C# as it turns the language into a more productive tool.
Just foillow up C#'s evolution since C# 2.0:
From delegates provided as regular methods to anonymous delegates.
LINQ, lambda-style delegates/expression trees.
Expression-bodied methods.
...and expression-bodied accessors! And probably future C# versions will introduce even more functional programming-style syntax and grammar.
You'll notice they removed the 'return' syntax, this was done (from what I've read) to make it more clear that they aren't functions (and when reflected can't be treated as functions and can't be made into delegates) but rather this kind of 'pseudo-function' (if you get what I'm trying to well get at).
So basically its to make it more clear that the getter is linking this this variable and the repeating for the setter. It also is because in newer versions you can do something like
public int MyInt => x ? y:z;
Which represents
public int MyInt
{
get
{
return x ? y:z;
}
}
Also both syntax should work, its just a new syntax that they added to bring it in line with the above example.
I know I am adding this details after a year, but just understood that my VS 2017 generated new syntax on my web user control, and that does not reflect on the aspx file when I wanted to set a value for it.
like
private bool _ShowBankDetailPanel = false; //To Show Bank details section in registration
public bool ShowBankDetailPanel { get => _ShowBankDetailPanel; set => _ShowBankDetailPanel = value; }
and on ASPX side you will NOT have property like
it is only recognize
old style getter setter....(I experience this,,, but I am be wrong)

Can I add methods to an Objective-C enum?

In Java, I have an enum like:
public enum Toppings {
PEPPERONI,
EXTRA_CHEESE,
SECRET_SAUCE;
#Override
public String toString() {
switch(this) {
case EXTRA_CHEESE: return "Extra Cheese";
case SECRET_SAUCE: return "Secret Sauceā„¢";
}
String name = name();
return name.charAt(0) + name.substring(1, name.length()).replace('_', ' ').toLowerCase();
}
}
I want to re-made this in Objective-C. So far, I've done this:
NS_ENUM(NSInteger, Toppings) {
PEPPERONI,
EXTRA_CHEESE,
SECRET_SAUCE
};
And then I was stumped. How would I make the toString() method? I know it's rather complex and uses some Java-specific behaviors, but I'm sure there's a way.
The only thing that comes to mind is to have a separate helper class with this functionality, but that seems a bit much, doesn't it?
Unfortunately, there is no way to add methods to an Objective-C enum. (Sidenote: you can add methods to a Swift enum.)
Traditionally, a standalone function would be used for this purpose, with a body similar to your Java method:
NSString* NSStringFromToppings(Toppings toppings)
{
switch (toppings)
{
case PEPPERONI: return #"Pepperoni";
case EXTRA_CHEESE: return #"Extra Cheese";
case SECRET_SAUCE: return #"Secret Sauce";
}
}
(Sidenote: you should name your enum Topping instead of Toppings--you can see how the code above would be clearer with a singular type name. You should also add a two- or three-letter prefix to all your type names (and this function) to avoid naming collisions.)
NSString * const ToppingsList[] = {
[PEPPERONI] = #"Pepperoni",
[EXTRA_CHEESE] = #"Extra Cheese",
[SECRET_SAUCE] = #"Secret Sauce",
};
NSLog("Topping: %#", ToppingList[PEPPERONI]);
After declaring your enum, you can add this to use type string. It seems like toString() method
EDIT: Meanwhile #andyvn22 is right. There is no way to add methods to enums in Objective-C. I just gave a solution for using enums with string.
Yeah, it's not as straightforward as in, say, Java or .NET. However, I think that option 2 of yar1vn's answer looks ok:
Convert objective-c typedef to its string equivalent
You could also add enum serialization as an NSString extension, making it possible to ask NSString to give you a string based on your enum.
No, there is no way to declare a method in an enum using Objective-C.
However, you can use an enum as a parameter to any method. This might be a solution for you:
typedef NS_ENUM(int, PatientActivity)
{
Exercise = 101,
Smoke,
Alcohol
};
- (void)getPatientDetail:(NSString *)PatID withActivity:(enum PatientActivity) activity;

Type hinting v duck typing

Using the following simple Example (coded in php):
public function doSomething(Registry $registry)
{
$object = $registry->getData('object_key');
if ($object) {
//use the object to do something
}
}
public function doSomething($registry)
{
$object = $registry->getData('object_key');
if ($object) {
//use the object to do something
}
}
What are the benefits of either approach?
Both will ultimately fail just at different points:
The first example will fail if an object not of type Registry is passed, and the second will fail if the object passed does not implement a getData method.
How do you choose when to use either approach?
Those are 2 different design approaches. The responsibility falls on the developer(s) to make sure either methods won't fail.
Type hinting is a more robust approach while duck typing gives you more flexibility.

How can I simplify my deserialization framework?

I have a Serialization interface which is designed to encapsulate the differences between XML/JSON/binary serialization for my application. It looks something like this:
interface Serialization {
bool isObject();
int opApply(int delegate(string member, Serialization value) del); //iterate object
...
int toInt(); //this part is ugly, but without template member overloading, I
long toLong(); //figure out any way to apply generics here, so all basic types
... //have a toType primitive
string toString();
}
class JSONSerialization : Serialization {
private JSON json;
...
long toLong() {
enforce(json.type == JSON_TYPE.NUMBER, SerializationException.IncorrectType);
return cast(long)json.toNumber();
}
...
}
So, what I then set up is a set of templates for registering type deserializers and calling them:
...
registerTypeDeserializer!Vec3(delegate Vec3(Serialization s) {
return Vec3(s[0].toFloat, s[1].toFloat, s[2].toFloat);
});
...
auto v = parseJSON("some file").deserialize!Vec3;
...
registerTypeDeserializer!Light(delegate Light(Serialization s) {
return new Light(s["intensity"].toFloat, s["position"].deserialize!Vec3);
});
This works well for structs and simple classes, and with the new parameter identifier tuple and parameter default value tuple I should even be able to add automatic deserializer generation. However, I don't really like the inconsistency between basic and user defined types, and more importantly, complex types have to rely on global state to acquire references:
static MaterialLibrary materials;
registerTypeDeserializer!Model(delegate Model(Serialization s) {
return new Model(materials.borrow(s["material"].toString), ...);
});
That's where it really falls apart. Because I can't (without a proliferation of register deserializer functions) pass other parameters to the deserializer, I'm having difficulty avoiding ugly global factories. I've thought about eliminating the deserialize template, and requiring a deserialize function (which could accept multiple parameters) for each user defined type, but that seems like a lot of work for e.g. POD structs.
So, how can I simplify this design, and hopefully avoid tons of boilerplate deserializers, while still allowing me to inject object factories appropriately, instead of assigning them globally?
Basic types can be read using readf \ formattedRead, so you can create a wrapper function that uses this formattedRead it possible, otherwise it uses a static function from the desired type to read the value. Something like this:
auto _readFrom(T)(string s){
static if(__traits(compiles,(readf("",cast(T*)(null))))){
T result;
formattedRead(s,"%s",&result);
return result;
}else{
return T.readFrom(s);
}
}

Does PetaPoco handle enums?

I'm experimenting with PetaPoco to convert a table into POCOs.
In my table, I've got a column named TheEnum. The values in this column are strings that represent the following enum:
public enum MyEnum
{
Fred,
Wilma
}
PetaPoco chokes when it tries to convert the string "Fred" into a MyEnum value.
It does this in the GetConverter method, in the line:
Convert.ChangeType( src, dstType, null );
Here, src is "Fred" (a string), and dstType is typeof(MyEnum).
The exception is an InvalidCastException, saying Invalid cast from 'System.String' to 'MyEnum'
Am I missing something? Is there something I need to register first?
I've got around the problem by adding the following into the GetConverter method:
if (dstType.IsEnum && srcType == typeof(string))
{
converter = delegate( object src )
{
return Enum.Parse( dstType, (string)src ) ;
} ;
}
Obviously, I don't want to run this delegate on every row as it'll slow things down tremendously. I could register this enum and its values into a dictionary to speed things up, but it seems to me that something like this would likely already be in the product.
So, my question is, do I need to do anything special to register my enums with PetaPoco?
Update 23rd February 2012
I submitted a patch a while ago but it hasn't been pulled in yet. If you want to use it, look at the patch and merge into your own code, or get just the code from here.
I'm using 4.0.3 and PetaPoco automatically converts enums to integers and back. However, I wanted to convert my enums to strings and back. Taking advantage of Steve Dunn's EnumMapper and PetaPoco's IMapper, I came up with this. Thanks guys.
Note that it does not handle Nullable<TEnum> or null values in the DB. To use it, set PetaPoco.Database.Mapper = new MyMapper();
class MyMapper : PetaPoco.IMapper
{
static EnumMapper enumMapper = new EnumMapper();
public void GetTableInfo(Type t, PetaPoco.TableInfo ti)
{
// pass-through implementation
}
public bool MapPropertyToColumn(System.Reflection.PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
// pass-through implementation
return true;
}
public Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo pi, Type SourceType)
{
if (pi.PropertyType.IsEnum)
{
return dbObj =>
{
string dbString = dbObj.ToString();
return enumMapper.EnumFromString(pi.PropertyType, dbString);
};
}
return null;
}
public Func<object, object> GetToDbConverter(Type SourceType)
{
if (SourceType.IsEnum)
{
return enumVal =>
{
string enumString = enumMapper.StringFromEnum(enumVal);
return enumString;
};
}
return null;
}
}
You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.
Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.
If you are using PetaPoco's T4 generation and you want enums in your generated type, you can use the PropertyType override in Database.tt:
tables["App"]["Type"].PropertyType = "Full.Namespace.To.AppType";
I you want to store the value of the enum instead of the index number (1,2,4 for example) you can locate the update function in PetaPoco class because the code is "managed" etc, when you add it as nuget package it will store the .cs file to your project. If we would have the enum variable Color = {red, yellow, blue}
Instead of:
// Store the parameter in the command
AddParam(cmd, pc.GetValue(poco), pc.PropertyInfo);
change to:
//enum?
if (i.Value.PropertyInfo.PropertyType.IsEnum)
{
AddParam(cmd, i.Value.GetValue(poco).ToString(), i.Value.PropertyInfo);
}
else
{
// Store the parameter in the command
AddParam(cmd, i.Value.GetValue(poco), i.Value.PropertyInfo);
}
It would store "yellow" instead of 2