TypeDescriptor does not recongnise date - c#

I'm having an ussue with the TypeDescriptor class.
I have a cookie which contains a date - the date is converted to a string and then back again using some helper methods.
One of my staple extension methods is used to do the conversion, however it throws a forced error because the date is not convertible back from a string.
Here's the message I output:
22/01/2015 14:29:15 could not be converted to DateTime
Looks like a DateTime to me!
The problem can be overcome by using Convert.ToDateTime(), so the code in general is ok. i also use it for dates elwhere with no problems to date.
The only difference is that I'm converting in the middle of a linq statement like this:
Set = new SortedSet<TrackedItem>(set
.Split(';')
.Select(s =>
{
var parts = s.Split(',');
return new TrackedItem(
parts[0].ConvertTo<int>(),
Convert.ToDateTime(parts[1]));
}));
Any ideas?
public static T ConvertTo<T>(this object obj, bool throwInvalid = false)
where T : IConvertible
{
// Object does not require converting.
if (obj is T) return (T)obj;
// Determine if object can be converted.
var type = typeof(T);
var converter = TypeDescriptor.GetConverter(type);
var isConvertible = converter != null && converter.IsValid(obj);
var error = string.Format("'{0}' could not be converted to type {1}", obj, type.Name);
// If no conversion is available, and defaults not allowed throw an error.
(!isConvertible && throwInvalid).ThrowTrue(error);
// If the object is convertible, convert it, else return the default(T).
return isConvertible ? (T)converter.ConvertFrom(obj) : default(T);
}

I'm guessing from your date example that you're running in the en-GB culture. Unfortunately, to draw liberally from this related q/a, IsValid always uses CultureInfo.InvariantCulture (US date format) to decide its answer. So when running in en-GB with a date such as your example, IsValid will return false; but ConvertFrom, which by default uses the current thread culture will succeed!
Interestingly, the latest docs for IsValid massively hedge the question of whether this is actually a bug:
The IsValid method is used to validate a value within the type
rather than to determine if value can be converted to the given type.
For example, IsValid can be used to determine if a given value is
valid for an enumeration type.
So really you shouldn't be using IsValid here at all - you should be doing what the same docs go on to suggest:
You can write your own WillConvertSucceed method by wrapping the
ConvertTo and ConvertFrom methods in exception blocks.
And in that method you can be sure to use the CultureInfo you actually care about.

Related

converting to string return null

while am trying to convert the return value of add method to string it is not returning any value in console.while i remove the tostring method it is returning value.if i write any character inside the double quote it is showing in console.
what is happening while am calling tostring method?
if i didn't put any double quote as parameter it is showing compile time error like (specify culture of string)
what is the purpose of specifying culture while converting int to string?
i think i can convert integer value to string by calling tostring method,why can't i do conversion in this scenario?
private static int Add(int x,int y)
{
return x+y;
}
static void Main(string[] args)
{
Console.WriteLine(Add(23,54).ToString(""));
Console.ReadKey();
}
thanks.
It's all about implementation;
From Int32.ToString(string)
If format is null or an empty string (""), the return value of this
instance is formatted with the general numeric format specifier ("G").
That's why .ToString("") is equal to .ToString() because
From Int32.ToString()
The ToString() method formats an Int32 value in the default ("G", or
general) format by using the NumberFormatInfo object of the current
culture.
I tried all cultures to format with .ToString("") and no culture returns null or empty string.
foreach (var c in CultureInfo.GetCultures(CultureTypes.AllCultures))
{
if((77).ToString("G", c) != "77")
Console.WriteLine (c.Name);
}
Blue line probably there is a plugin (maybe ReSharper) that warn you to use another overloads that takes CultureInfo as a parameter for example.
Use ToString with no parameters
Add(23,54).ToString()
Using the parameter you specified you set a culture for the string conversion.
More here.
simply specify your culture of string as string.empty
Console.WriteLine(Add(23,54).ToString(string.Empty));
Console.ReadKey();
Culture Name:"" (empty string)
Culture Identifier:0x007F
Language-Country/Region:invariant culture
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28v=vs.71%29.aspx
string.Empty is a read-only field whereas "" is a compile time constant.some Places they behave differently.

Coding practice to convert string variables to actual types

I have a service that validates the user input. So, in other layers I am just using the below statement to get the amount value assuming that it is already validated.
But while writing unit test cases, I realized this is failing. So, my question is do we need to ALWAYS try to parse the values whenever string values needs to be converted to actual types.
var amountValue = Convert.ToDecimal(string.Format("{0}.{1}", view.amount, view.fraction))
You should parse strings because that's what you actually want to do.
A type conversion is something different than parsing.
Imagine a case where in the US you separate decimals with a dot . and in EU you'd use a comma ,. You can't really know how the locale separates decimals and whatnot (especially dates are crucial and should be PARSED no CONVERTED).
That said, the rule user input => parse is quite straight forward.
Here is a convert method based on generics:
public static void Convert<T>(string text, out T value, CultureInfo culture) where T : IConvertible
{
if (typeof(T).IsEnum)
{
value = (T) Enum.Parse(typeof (T), text, true);
}
else
{
value = (T)System.Convert.ChangeType(text, typeof(T), culture);
}
}

How to convert boolean to localized string

There is any way to convert a boolean value to a localized string. I have tried:
var x = true;
var culture = new CultureInfo("en-US")
x.ToString(culture) // returns True
culture = new CultureInfo("pt-BR")
x.ToString(culture) // returns True, expected Verdadeiro
Or should I start typing the switch now to end before 2020?
Well, start typing because it's documented behaviour :)
Boolean.ToString(IFormatProvider)
Remarks
The provider parameter is reserved. It does not participate in the
execution of this method. This means that the
Boolean.ToString(IFormatProvider) method, unlike most methods with a
provider parameter, does not reflect culture-specific settings.
As #Michal pointed out, this is the documented behavior.
If your system supports many languages, you must have some sort of i18 support. Use that to convert a boolean value to string. You can add an extension method like so:
public string ToLocalizedString(this bool b)
{
return ...i18n version of true or false...
}

why var returnText = value as string not working?

I have a Convert method that implements IValueConverter. My first statement is
var returnText = value as string not working to take over the value as string. However, it doesn't work and when I was debugging, I found out the value of the "value" variable didn't assign over to returnText so the returnText is always null. It is odd. Does anybody know why?
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var returnText = value as string;
if (!string.IsNullOrEmpty(returnText))
{
.....
Problem and Solution
The problem is that as string does not convert, it just casts the object to a string. If that doesn't work it will produce null instead. The object must be of string type originally, in this case that is obviously not the case.
One option that would likely work in your case is to call .ToString() on the object like so:
var returnText = value.ToString();
but please note that this really does depend on your object type, and what it's .ToString() method actually produces. You may get a value that you do not expect.
Additional Recommendations
As Tim has commented, ToString() will throw an exception if the object is null to begin with. It is recommended to test for this before calling any method on the object. Something like this will do:
string returnText = null;
if(value != null)
returnText = value.ToString();
Further Reading
See here for more information. A couple of useful quotes from that link:
The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception.
and
Note that the as operator performs only reference conversions, nullable conversions, and boxing conversions. The as operator can't perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.
try
var returnText = value==null ? "": value.ToString();
Because this var returnText = value as string; means: Try to cast value as string if not, return null.
as (C# Reference) http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx
Why System.Convert.ToString() instead of .ToString()......
I'd rather use var returnText = System.Convert.ToString(value); because this will use the IConvertable interface. The ToString() could give a screwed-up result. (like classnames etc)
More info: Convert.ToString Method http://msdn.microsoft.com/en-us/library/astxcyeh.aspx

Providing DateTime values in OData

I'm currently writing a special client application to allow our unit tests to work with an OData interface using the XML structure for atom feeds.
All seems to be working properly, but i'm running into trouble when I need to pass a DateTime value as property.
I've written the following code that extracts the DateTime value from the property of the object and stores it in a specific format:
private static void GenerateProperty<T>(StringBuilder xml, T obj, PropertyInfo info)
{
// Extract the information about the property if it contains a value.
if (info.GetValue(obj, null) == null) return;
string type = info.GetGetMethod().ReturnType.ToString().Split('.').Last();
string value = info.GetValue(obj, null).ToString();
if (type == "DateTime")
value = ((DateTime)info.GetValue(obj, null)).ToString("yyyy-mm-ddThh:mm:ss");
if (type == "Boolean") value = value.ToLower();
// Append the property to the generated XML.
xml.Append(type.ToLower().Equals("string") ?
string.Format("<d:{0}>{1}</d:{0}>", info.Name, value) :
string.Format("<d:{0} m:type=\"Edm.{1}\">{2}</d:{0}>", info.Name, type, value));
}
The code is heavy on reflection, but that's beside the point. The values returned by this code for a DateTime are in the following format: 2011-49-13T11:49:41Z
However, i'm receiving the following error from my OData Service:
Error processing request
stream. Error encountered in converting the value from request payload
for property 'Created' to type 'System.DateTime', which is the
property's expected type. See inner exception for more
detail.
The string '2011-49-13T11:49:41Z' is not a valid AllXsd
value.
System.FormatException
at System.Xml.XmlConvert.ToDateTime(String s,
XmlDateTimeSerializationMode dateTimeOption)
 at
System.Data.Services.Parsing.WebConvert.StringToPrimitive(String text,
Type targetType)
 at
System.Data.Services.Serializers.PlainXmlDeserializer.ConvertValuesForXml(Object
value, String propertyName, Type typeToBeConverted)
So apparently it doesn't understand the DateTime format, but when I look at the documentation that's posted here: http://www.odata.org/developers/protocols/overview#AbstractTypeSystem
I'd expect it to be valid. Anyone have any experience with this?
yyyy-mm-ddThh:mm:ss
should be
yyyy-MM-ddTHH:mm:ssZ
ToString("O") will solve the problem too.

Categories