Is there any way to detect the type from a given string input?
Eg:
string input = "07/12/1999";
string DetectType( s ) { .... }
Type t = DetectType(input); // which would return me the matched datatype. i.e. "DateTime" in this case.
Would I have to write this from scratch?
Just wanted to check if anybody knows of a better way before I went about it.
Thanks!
I'm pretty sure you'll have to write this from scratch - partly because it's going to be very strictly tailored to your requirements. Even a simple question such as whether the date you've given is December 7th or July 12th can make a big difference here... and whether your date formats are strict, what number formats you need to support etc.
I don't think I've ever come across anything similar - and to be honest, this sort of guesswork usually makes me nervous. It can be hard to get parsing right even when you know the data type, let alone when you're guessing at the data type to start with :(
You got to know something about the expected type.
If you do you could use TypeConverter e.g.:
public object DetectType(string stringValue)
{
var expectedTypes = new List<Type> {typeof (DateTime), typeof (int)};
foreach (var type in expectedTypes)
{
TypeConverter converter = TypeDescriptor.GetConverter(type);
if (converter.CanConvertFrom(typeof(string)))
{
try
{
// You'll have to think about localization here
object newValue = converter.ConvertFromInvariantString(stringValue);
if (newValue != null)
{
return newValue;
}
}
catch
{
// Can't convert given string to this type
continue;
}
}
}
return null;
}
Most system types have their own type converter, and you could write your own using the TypeConverter attribute on your class, and implementing your own converter.
Related
I'm trying to parse my variable to its string representation typeName.
string typeName = property.PropertyType.ToString();
var propertyItem = (typeName)property.GetValue(templateData, null);
The string typeName should be the 'Type' of the property I have in my Model so somehow i want to parse it to that type. (at this moment it is List(InvoiceModel), but this may vary)
I hope this is enough information, otherwise please notify me. Thanks in advance.
property.GetValue returns the required object. From your code sample it seems that you don't know the object's type at compile time.
It is not possible to cast that object using (typename), and there is no use, because still you won't know the real type at compile time.
What you probably want to do is to use dynamic:
dynamic propertyItem = property.GetValue(templateData, null);
I think what you are looking for is property.GetType().ToString();
though you can't just put the varable in brackets to convert you need to use reflection to create the type
That said this entire idea is a bad idea, from the look of your code i think your trying to create some form of MetaData, if so then i would use an Enum to define your allowed datatypes, and i would only allow the simplest ones int, double, string, datetime etc and possibly an array's of such
in that case you would then do,
if(Property.Type == AllowedTyoes.String)
{
string stringval = Property.Value as string;
//use the string for a string safe function
}
if(Property.Type == AllowedTyoes.Int)
{
string stringval = Property.Value as string;
int tmp;
if(int.TryParse(stringval,out tmp))
{
//use the int for a int safe function
}
}
This is my first time using StackOverflow myself. I have found many answers to many of my question here before, and so I thought I would try asking something myself.
I'm working on a small project and I am a bit stuck right now. I know ways to solve my problem - just not the way I want it to be solved.
The project includes an NBT parser which I have decided to write myself since it will be used for a more or less custom variation of NBT files, though the core principle is the same: a stream of binary data with predefined "keywords" for specific kinds of tags. I have decided to try and make one class only for all the different types of tags since the structure of the tags are very similar - they all contain a type and a payload. And this is where I am stuck. I want the payload to have a specific type that, when an explicit conversion is done implicitly, throws an error.
The best I could come up with is to make the payload of type Object or dynamic but that will allow all conversions done implicitly:
Int64 L = 90000;
Int16 S = 90;
dynamic Payload; // Whatever is assigned to this next will be accepted
Payload = L; // This fine
Payload = S; // Still fine, a short can be implicitly converted to a long
Payload = "test"; // I want it to throw an exception here because the value assigned to Payload cannot be implicitly cast to Int64 (explicit casting is ok)
Is there any way of doing this? I would like to solve it by somehow telling C# that from now on, even though Payload is dynamic, it will throw an exception if the assigned value cannot be implicitly converted to the type of the current value - unless, of course, it is done explicitly.
I am open to other ways of accomplishing this, but I would like to avoid something like this:
public dynamic Payload
{
set
{
if(value is ... && Payload is ...) { // Using value.GetType() and Payload.GetType() doesn't make any difference for me, it's still ugly
... // this is ok
} else if(...) {
... // this is not ok, throw an exception
}
... ... ...
}
}
Have you considered using generics?
This would automatically give you compile-time checking on which conversions are allowed.
class GenericTag<T>
{
public GenericTag(T payload)
{
this.Payload = payload;
}
public T Payload { set; get; }
}
// OK: no conversion required.
var tag2 = new GenericTag<Int64>(Int64.MaxValue);
// OK: implicit conversion takes place.
var tag1 = new GenericTag<Int64>(Int32.MaxValue);
// Compile error: cannot convert from long to int.
var tag4 = new GenericTag<Int32>(Int64.MaxValue);
// Compile error: cannot convert from string to long.
var tag3 = new GenericTag<Int64>("foo");
If you know you will need Int64, why not to use Convert.ToInt64?
If I have (in .NET/C#) for instance a variable of type long I can convert it to a formatted string like:
long value = 12345;
string formattedValue = value.ToString("D10"); // returns "0000012345"
If I specify a format which isn't valid for that type I get an exception:
long value = 12345;
string formattedValue = value.ToString("Q10"); // throws a System.FormatException
Question: Is there a way to check if a format specifier is valid (aside from trying to format and catching the exception) before I apply that format, something like long.IsFormatValid("Q10")?
Thanks for help!
I've not tried this but I would think you could create an extension method such as:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static bool IsFormatValid<T>(this T target, string Format)
where T : IFormattable
{
try
{
target.ToString(Format, null);
}
catch
{
return false;
}
return true;
}
}
}
which you could then apply thus:
long value = 12345;
if (value.IsFormatValid("Q0"))
{
...
Rather than creating a check for that I'd suggest that it might be better that the developers reads the documentation to find out what's allowed where.
However, if there is a problem with a lot of typos being made, I suppose you could write a lookup table from the information on that page. Though that could just give you a false sense of security in that you'd get people making mistakes between valid format specifiers (writing an f but they meant e etc).
Edited to remove confused bit about TryParse/Parse.
I have a method that converts a number from string to the T, e.g int
public static T GetItemIdFromUrl<T>(string itemName)
{
try
{
...
int ad_id = int.Parse(stringNumber);
return (T)(object)ad_id;
}
catch
{
return (T)(object)-1;
}
}
but as a result I have a hex code 0xffffffa5 instead of 91. Why ?
Well, it's hard to know for sure why it's returning 0xffffffa5 without knowing the input string, but your code is going to throw an exception if T is anything other than either int or a enum with an underlying base type of int. For example, it will throw if T is double. Your method isn't really generic - the value it's trying to return is always an int. Why is your method not just declared to return int? If you want to convert from int to some other type (double, long, whatever) just let that conversion be done on assignment. The unboxing conversion in your code will not work unless T is int or an appropriate enum (the latter of which seems unlikely).
One thing to note is that 0xffffffa5 is the bit pattern for -91. Is it possible that you've only seen that result in the debugger, and the result is meant to be -91 rather than 91?
Even if your intention is to genericize the handling of different numeric types (e.g., double, decimal, etc.), this isn't the way to do it. When you box to object, and then unbox to T, it will only work if the boxed type actually is T. In other words, it will not perform a type conversion for you.
The only way (that I know of) to do the type conversion from object to whatever you want is by using the Convert class:
return (T)Convert.ChangeType(ad_id, typeof(T));
Even this is fragile, obviously (as it won't work if T is any non-numeric type); but at least it won't throw exceptions in pretty much all cases you're trying to cover. (Your method as it is currently implemented will throw for every T except int.)
I think you have a fundamental misunderstanding of what generics are and how they're supposed to be used. The whole point of generics is to have the benefit of working on different types while not losing type safety which is what happens when you cast to object
That being said Jon Skeet is probably correct that it's probably the way the debugger is displaying the result.
I think you are doing something else where you show the ellipses (...):
try
{
...
int ad_id = int.Parse(stringNumber);
return (T)(object)ad_id;
}
because I tried your sample and I get a return int.
You really don't have any way, currently, of ensuring your return is going to work. You method will rely on very specific information. Provide a bit more info where you have the ellipses and a better solution can be recommended. As Jon mentions, a nullable int? would be better. Test for the condition and if it isn't a correct return, you can check for myInt.HasValue.
I have been pondering a complete solution this problem and came up with the following:
static List<Type> numerics = new List<Type>();
static void Main(string[] args)
{
numerics.Add(typeof(Decimal));
numerics.Add(typeof(Double));
numerics.Add(typeof(Int16));
numerics.Add(typeof(Int32));
numerics.Add(typeof(Int64));
numerics.Add(typeof(Single));
numerics.Add(typeof(UInt16));
numerics.Add(typeof(UInt32));
numerics.Add(typeof(UInt64));
Console.WriteLine("StringNumber 55: {0} {1}", typeof(int), GetItemIdFromUrl<int>("55"));
Console.WriteLine("StringNumber 5B99: {0} {1}", typeof(int), GetItemIdFromUrl<int>("5B99"));
Console.ReadKey();
}
public static T GetItemIdFromUrl<T>(string stringNumber)
{
try
{
if (numerics.Contains(typeof(T)))
return (T)Convert.ChangeType(stringNumber, typeof(T));
else
return default(T);
}
catch (ArgumentException argEx)
{
Console.WriteLine("Exception\r\n{0}", argEx);
return default(T);
}
catch (FormatException formatEx)
{
Console.WriteLine("Exception\r\n{0}", formatEx);
return default(T);
}
}
From the 2nd WriteLine you will be able to see what happens if an invalid numeric is passed. Of course, I included the Exception messages just so you could see what they would return. It might not be a glamorous solution, but I think it is viable.
I also came up with this:
public static class GetNumeric<T>
{
public static Func<string, T> Value = stringValue => (T)Convert.ChangeType(stringValue, typeof(T));
}
Although I would still wrap the call in a try/catch block.
I guess this could also be asked as to how long the created type name is attached to an anonymous type. Here's the issue:
A blog had something like this:
var anonymousMagic = new {test.UserName};
lblShowText.Text = lblShowText
.Text
.Format("{UserName}", test);
As sort of a wish list and a couple ways to go at it. Being bored and adventurous I took to creating an string extension method that could handle this:
var anonymousMagic = new {test.UserName, test.UserID};
lblShowText.Text = "{UserName} is user number {UserID}"
.FormatAdvanced(anonymousMagic);
With the idea that I would get the property info from the anonymous type and match that to the bracketted strings. Now with property info comes reflection, so I would want to save the property info the first time the type came through so that I wouldn't have to get it again. So I did something like this:
public static String FormatAdvanced(this String stringToFormat, Object source)
{
Dictionary<String, PropertyInfo> info;
Type test;
String typeName;
//
currentType = source.GetType();
typeName = currentType.Name;
//
//info list is a static list for the class holding this method
if (infoList == null)
{
infoList = new Dictionary<String, Dictionary<String, PropertyInfo>>();
}
//
if (infoList.ContainsKey(typeName))
{
info = infoList[typeName];
}
else
{
info = test.GetProperties()
.ToDictionary(item => item.Name);
infoList.Add(typeName, info);
}
//
foreach (var propertyInfoPair in info)
{
String currentKey;
String replacement;
replacement = propertyInfoPair.Value.GetValue(source, null).ToString();
currentKey = propertyInfoPair.Key;
if (stringToFormat.Contains("{" + currentKey + "}"))
{
stringToFormat = stringToFormat
.Replace("{" + currentKey + "}", replacement);
}
}
//
return stringToFormat;
}
Now in testing, it seems to keep the name it created for the anonymous type so that the second time through it doesn't get the property info off the type but off the dictionary.
If multiple people are hitting this method at the same time, is it pretty much going to work in a Session like fassion; IE the names of the types will be specific to each instance of the program? Or would it be even worse than that? At what point does that name get chucked and overwritten?
It never does. The type is generated at compile-time and you can consider it constant and unique throughout the life of the app-domain.
I question the value of this function though. The obvious first reason is because you don't have much of the functionality of the Format method on the String class (no escape for brackets, no formatting of values in the brackets, etc, etc).
The second is that it basically links the format string to the type being passed in, so they are not swapped out easily. If I had two classes which had the same conceptual value, but different properties naming it, I have to change my format string to display it with your method to compensate for the fact that the property name is embedded in the format string.
Anonymous types are generated at compile time, and so the reflection names should be static as long as you don't re-compile the assembly.
There is a detailed post here that describes the names, but I believe what you are doing is safe.
I have two things to say, but this isn't really an answer.
First of all, the Dictionary doesn't have to have a string key; the key could be the actual type. i.e. it could be a Dictionary<Type, Dictionary<String, PropertyInfo>>. That would be faster because you don't have to get the type name, and less error prone - what if I send that method two non-anonymous types with the same name but different namespaces?
Second, you should read Phil Haack's recent blog post about this subject. It contains a full implementation of such a method.