I have a method that returns a type of object based on the given column (a database class). However, when I assign the object the compiler throws an error saying it cannot implicitly convert type of object to int. How can I convert it without casting?
It looks better as:
this.Id = datum["Id"];
But now I have to include a cast, which makes the code a bit less clean and harder to code:
this.Id = (int)datum["Id"];
Here's my code:
public object this[string name]
{
get
{
object result;
if (this.Dictionary.ContainsKey(name))
{
if (this.Dictionary[name] is DBNull)
{
result = null;
}
else if (this.Dictionary[name] is byte && Meta.IsBool(this.Table, name))
{
result = (byte)this.Dictionary[name] > 0;
}
else
{
result = this.Dictionary[name];
}
}
else
{
result = default(object);
}
return result;
}
set
{
if (value is DateTime)
{
if (Meta.IsDate(this.Table, name))
{
value = ((DateTime)value).ToString("yyyy-MM-dd");
}
else if (Meta.IsDateTime(this.Table, name))
{
value = ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
}
if (this.Dictionary.ContainsKey(name))
{
this.Dictionary[name] = value;
}
else
{
this.Dictionary.Add(name, value);
}
}
}
You could change your indexer signature to:
public dynamic this[string name]
That would then make the conversion dynamic at execution time.
Personally, I prefer the cast approach though. It makes it clear that this is something that can fail - that you're telling the compiler that you have information which isn't available to it.
As an aside, your code can be written rather more simply, taking advantage of Dictionary<,>.TryGetValue and the behaviour of the dictionary indexer for setting:
public object this[string name]
{
get
{
object result;
if (Dictionary.TryGetValue(name, out result))
{
if (result is DBNull)
{
result = null;
}
else if (result is byte && Meta.IsBool(this.Table, name))
{
result = (byte) result > 0;
}
}
return result;
}
set
{
// TODO: Byte/bool conversions?
if (value is DateTime)
{
// Note use of invariant culture here. You almost certainly
// want this, given the format you're using. Preferably,
// avoid the string conversions entirely, but...
DateTime dateTime = (DateTime) value;
if (Meta.IsDate(this.Table, name))
{
value = dateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
}
else if (Meta.IsDateTime(this.Table, name))
{
value = dateTime.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
}
}
Dictionary[name] = value;
}
}
Use class Convert:
Convert.ToInt32(datum["Id"]);
If you didn't need to state in your code that you are casting from object to int, then the programming language would not be helping you avoid mistakes.
C# does have a feature where you can switch off static type checking for specific variables: make your indexer return dynamic:
public dynamic this[string name]
Then you'll be able to say:
int n = datum["Id"];
But the downside is that you won't find out if this is correct until runtime.
You can do an extension method.
Create a class like this.
public static class ExtensionMethods
{
public static int AsInt(this object obj)
{
return (int)obj; // add additional code checks here
}
}
Then in your actual code all you have to do is call the extension method like this.
this.Id = datum["Id"].AsInt();
I know this may look the same as the cast but it happens underneath the method call AsInt and your code is cleaner and easier to read since AsInt is fluent and definitive.
Related
I have an object. Usually it is either long or string, so to simplify the code let's assume just that.
I have to create a method that tries to convert this object to a provided enum. So:
public object ToEnum(Type enumType, object value)
{
if(enumType.IsEnum)
{
if(Enum.IsDefined(enumType, value))
{
var val = Enum.Parse(enumType, (string)value);
return val;
}
}
return null;
}
With strings it works well. With numbers it causes problems, because a default underlying type for enum is int, not long and IsDefined throws an ArgumentException.
Of course I can do many checks, conversions or try-catches.
What I want is to have a clean and small code for that.
Any ideas how to make it readable and simple?
It feels to me like you only actually want to handle three cases:
Input is already the right type
Strings
Integers in various types
I believe this will do what you want for valid input:
public object ToEnum(Type enumType, object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (enumType == null)
{
throw new ArgumentNullException("type");
}
if (!enumType.IsEnum)
{
return false;
}
string valueString = value as string;
if (valueString != null)
{
return Enum.IsDefined(enumType, value) ? Enum.Parse(enumType, valueString) : null;
}
if (value.GetType() == enumType)
{
return value;
}
// This appears to handle longs etc
return Enum.ToObject(enumType, value);
}
However, that will return a value of the right type even for undefined values. If you don't want that, change the last part to:
object candidate = Enum.ToObject(enumType, value);
return Enum.IsDefined(enumType, candidate) ? candidate : null;
Also, this will still throw an exception if you pass in a floating point number, or something like that. If you don't want that behaviour, you'll need to have a set of all the types you do want to accept, and check against that first.
Try this
public object ToEnum<T>(object value)
{
var type = typeof(T);
if (type.IsEnum)
{
int numberVal;
if (!int.TryParse(value.ToString(), out numberVal) && value.GetType() != typeof(string))
{
return null;
}
value = numberVal;
if (Enum.IsDefined(type, value))
{
T result = (T)Enum.Parse(type, value.ToString());
return result;
}
}
return null;
}
I have the following getter and setter method:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
if (partner == null)
{
// something like partner = " ";
}
return partner;
}
set
{
partner = value;
}
}
In the if clause i want to set partner = " ". But of course this isn't working, cause partner is a Typ a the class Ansprechpartner.
Is there a way to do something equivalent, so that partner returns an empty string if (partner == null)?
Please help
is Ansprechpartner your own class?
If it is, than you can return your own defenition of an "empty" Ansprechpartner
return Ansprechpartner.Empty;
and then define the empty property
public class Ansprechpartner
{
public static Ansprechpartner Empty
{
get
{
//generate an empty Ansprechpartner and return it here
}
}
You could override the ToString method from the Ansprechpartner and use a flag attribute like this:
public override ToString()
{
if (FlagAtrribute == null) //Or if it is a string, you could String.IsNullOrEmpty(FlagAtrribute)
{
return "";
}
return FlagAtrribute.ToString();
}
And in your getter just return a new empty instance of the Ansprechpartner class
get
{
if (partner == null)
{
partner = new Ansprechpartner();
}
return partner;
}
And in your code, do something like this:
MyClass.Partner.ToString();
If you change your return type from Ansprechpartner to object you can return anything you would like that derives from object. But I would strongly disagree with taking this approach. If you will want to rethink you're entire approach.
Your property doesn't actually appear to be working with strings, in which case returning a string would be an error.
However, answering your question directly of how to return a string, try something like this:
get
{
if (partner == null)
return String.Empty;
else
return partner;
}
}
Or, better yet:
get
{
return partner ?? String.Empty;
}
you could do something like:
get
{
if (partner == null)
return new Ansprechpartner() {whatever = ""};
else
return partner;
}
In my opinion there is a straightforward way to get exacly what you ask, that is to ensure that it is syntactically correct the folloging:
get
{
if (partner == null)
{
return = "";
}
return partner;
}
The way is to provide an implicict cast operator for the class. Thanks to implicit cast operator, the String.Empty or "" can be automatically casted to Ansprechpartner type, then it is perfectly legal the sysntax you use for the getter.
but what is a implicict cast operator ?
You can even see the question: How do I provide custom cast support for my class? for more detail.
I preferred, however, directly test the code for your class: the code used to successfully test it is the following:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
// legal assignment thanks to **public static implicit operator Ansprechpartner(string s)**
return partner ?? String.Empty;
}
set
{
partner = value;
}
}
We also try to make the inverse: thanks to public static implicit operator string(Ansprechpartner a) we see that is possible to assign an Empty string to a Ansprechpartner instance variabile
public void test_method()
{
Ansprechpartner s = String.Empty;
}
In the Ansprechpartner class we define cast operators
class Ansprechpartner
{
public static implicit operator Ansprechpartner(string s) {
// put your conversion logic here
// .. i.e: you can simply pass string s to a Ansprechpartner constructor
Ansprechpartner a = new Ansprechpartner();
return a;
}
public static implicit operator string(Ansprechpartner a)
{
if (a == null)
return "";
else
return a.ToString();
}
public Ansprechpartner()
{
}
public override string ToString()
{
return Value;
}
}
That's it, leave a comment if something has not been explained.
I have a class named config with two string fields named key paramValue and parameterPath.
When I apply the ChooseType method of the class, the method has to return one variable paramValue in different types (Int or bool or String).
I implemented it as follow:
class ConfigValue
{
public string paramPath;
private string paramValue;
public enum RetType {RetInt, RetBool, RetString};
public T PolimorphProperty<T>(RetType how)
{
{
switch (how)
{
case RetType.RetInt:
return (dynamic)int.Parse(paramValue);
case RetType.RetBool:
return (dynamic)Boolean.Parse(paramValue);
case RetType.RetString:
return (T)(object)paramValue;
default:
throw new ArgumentException("RetType not supported", "how");
}
}
}
}
My question is how can i access to the PolimorphProperty method in ConfigValue class, to retrive for examlple paramValue Int type.
Having both T and RetType is redundant. It should be something like this:
class ConfigValue
{
public string paramPath;
private string paramValue;
public T PolimorphProperty<T>()
{
return (T)Convert.ChangeType(paramValue, typeof(T));
}
}
Call it like configValue.PolimorphProperty<int>().
Or if you need to implement the type conversion manually, you can do something like this:
class ConfigValue
{
public string paramPath;
private string paramValue;
public T PolimorphProperty<T>()
{
if (typeof(T) == typeof(MySpecialType))
return (T)(object)new MySpecialType(paramValue);
else
return (T)Convert.ChangeType(paramValue, typeof(T));
}
}
I think following code best matches what you want (i have tested it before writing here...)
public T PolimorphProperty<T>()
{
object tt = Convert.ChangeType(paramValue, typeof(T));
if (tt == null)
return default(T);
return (T) tt;
}
And you can call the code like this:
int ret = cv.PolimorphProperty<int>();
Notes:
You really do not need to pass anything in the param list to determine the type of the returned value.
Make sure you put try-catch wherever you are checking the appropraite type for your future usage.
Is there easyer way to parse in c# then this:
float temp;
if (float.TryParse(quantity.ToString(), out temp))
{
noteProduct.Quantity = temp;
}
Thanks
You can of course use float.Parse("string") - but it will throw exception if it can't parse it.
For me this is good and safe way of parsing.
TryParse is the best way, if you want to avoid possible exceptions.
If you are certain that quantity will always be a valid float you can simply use Parse:
noteProduct.Quantity = float.Parse(quantity.ToString());
However, this will throw an exception if quantity.ToString() is not a valid float.
As others have said, yes there are easier ways, but that doesn't mean you should necessarily use them. Easier does not always mean better. In this example I'd actually recommend you make your parsing more complicated - by making it culture sensetive..
float temp;
if (Single.TryParse(quantity.ToString(), NumberStyles.Float, CultureInfo.CurentCulture, out temp)
{
noteProduct.Quantity = temp;
}
This is how I solved it. This is more easier to use instead of declaring temp variables and make if statements.
public class Parsers
{
private Parsers() { }
public static void SetLong(ref long item, object value)
{
long temp;
if (value != null && long.TryParse(value.ToString(), out temp)) { item = temp; }
}
public static void SetDateTime(ref DateTime item, object value)
{
DateTime temp;
if (value != null && DateTime.TryParse(value.ToString(), out temp)) { item = temp; }
}
public static void SetInt(ref int item, object value)
{
int temp;
if (value != null && int.TryParse(value.ToString(), out temp)) { item = temp; }
}
public static void SetString(ref string item, object value)
{
if (value != null) { item = value.ToString(); }
}
}
I am trying to combine a bunch of similar methods into a generic method. I have several methods that return the value of a querystring, or null if that querystring does not exist or is not in the correct format. This would be easy enough if all the types were natively nullable, but I have to use the nullable generic type for integers and dates.
Here's what I have now. However, it will pass back a 0 if a numeric value is invalid, and that unfortunately is a valid value in my scenarios. Can somebody help me out? Thanks!
public static T GetQueryString<T>(string key) where T : IConvertible
{
T result = default(T);
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
result = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
What if you specified the default value to return, instead of using default(T)?
public static T GetQueryString<T>(string key, T defaultValue) {...}
It makes calling it easier too:
var intValue = GetQueryString("intParm", Int32.MinValue);
var strValue = GetQueryString("strParm", "");
var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified
The downside being you need magic values to denote invalid/missing querystring values.
I know, I know, but...
public static bool TryGetQueryString<T>(string key, out T queryString)
What about this? Change the return type from T to Nullable<T>
public static Nullable<T> GetQueryString<T>(string key) where T : struct, IConvertible
{
T result = default(T);
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
result = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
Convert.ChangeType() doesn't correctly handle nullable types or enumerations in .NET 2.0 BCL (I think it's fixed for BCL 4.0 though). Rather than make the outer implementation more complex, make the converter do more work for you. Here's an implementation I use:
public static class Converter
{
public static T ConvertTo<T>(object value)
{
return ConvertTo(value, default(T));
}
public static T ConvertTo<T>(object value, T defaultValue)
{
if (value == DBNull.Value)
{
return defaultValue;
}
return (T) ChangeType(value, typeof(T));
}
public static object ChangeType(object value, Type conversionType)
{
if (conversionType == null)
{
throw new ArgumentNullException("conversionType");
}
// if it's not a nullable type, just pass through the parameters to Convert.ChangeType
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
// null input returns null output regardless of base type
if (value == null)
{
return null;
}
// it's a nullable type, and not null, which means it can be converted to its underlying type,
// so overwrite the passed-in conversion type with this underlying type
conversionType = Nullable.GetUnderlyingType(conversionType);
}
else if (conversionType.IsEnum)
{
// strings require Parse method
if (value is string)
{
return Enum.Parse(conversionType, (string) value);
}
// primitive types can be instantiated using ToObject
else if (value is int || value is uint || value is short || value is ushort ||
value is byte || value is sbyte || value is long || value is ulong)
{
return Enum.ToObject(conversionType, value);
}
else
{
throw new ArgumentException(String.Format("Value cannot be converted to {0} - current type is " +
"not supported for enum conversions.", conversionType.FullName));
}
}
return Convert.ChangeType(value, conversionType);
}
}
Then your implementation of GetQueryString<T> can be:
public static T GetQueryString<T>(string key)
{
T result = default(T);
string value = HttpContext.Current.Request.QueryString[key];
if (!String.IsNullOrEmpty(value))
{
try
{
result = Converter.ConvertTo<T>(value);
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
You can use sort of Maybe monad (though I'd prefer Jay's answer)
public class Maybe<T>
{
private readonly T _value;
public Maybe(T value)
{
_value = value;
IsNothing = false;
}
public Maybe()
{
IsNothing = true;
}
public bool IsNothing { get; private set; }
public T Value
{
get
{
if (IsNothing)
{
throw new InvalidOperationException("Value doesn't exist");
}
return _value;
}
}
public override bool Equals(object other)
{
if (IsNothing)
{
return (other == null);
}
if (other == null)
{
return false;
}
return _value.Equals(other);
}
public override int GetHashCode()
{
if (IsNothing)
{
return 0;
}
return _value.GetHashCode();
}
public override string ToString()
{
if (IsNothing)
{
return "";
}
return _value.ToString();
}
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>(value);
}
public static explicit operator T(Maybe<T> value)
{
return value.Value;
}
}
Your method would look like:
public static Maybe<T> GetQueryString<T>(string key) where T : IConvertible
{
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
return new Maybe<T>();
}
}
return new Maybe<T>();
}
I like to start with a class like this
class settings
{
public int X {get;set;}
public string Y { get; set; }
// repeat as necessary
public settings()
{
this.X = defaultForX;
this.Y = defaultForY;
// repeat ...
}
public void Parse(Uri uri)
{
// parse values from query string.
// if you need to distinguish from default vs. specified, add an appropriate property
}
This has worked well on 100's of projects. You can use one of the many other parsing solutions to parse values.