How to insert into a generic parameter in C #?

I am trying to write a generalized method to get the XElement value in a strongly typed form. Here is what I have:

 public static class XElementExtensions { public static XElement GetElement(this XElement xElement, string elementName) { // Calls xElement.Element(elementName) and returns that xElement (with some validation). } public static TElementType GetElementValue<TElementType>(this XElement xElement, string elementName) { XElement element = GetElement(xElement, elementName); try { return (TElementType)((object) element.Value); // First attempt. } catch (InvalidCastException originalException) { string exceptionMessage = string.Format("Cannot cast element value '{0}' to type '{1}'.", element.Value, typeof(TElementType).Name); throw new InvalidCastException(exceptionMessage, originalException); } } } 

As you can see in the First attempt GetElementValue , I'm trying to jump from the line -> object -> TElementType. Unfortunately, this does not work for an integer test case. When performing the following test:

 [Test] public void GetElementValueShouldReturnValueOfIntegerElementAsInteger() { const int expectedValue = 5; const string elementName = "intProp"; var xElement = new XElement("name"); var integerElement = new XElement(elementName) { Value = expectedValue.ToString() }; xElement.Add(integerElement); int value = XElementExtensions.GetElementValue<int>(xElement, elementName); Assert.AreEqual(expectedValue, value, "Expected integer value was not returned from element."); } 

I get the following exception when GetElementValue<int> is called:

System.InvalidCastException: Unable to set the value of element '5' for input 'Int32'.

Do I have to handle each casting case (or at least numerical) separately?

+6
generics casting c # linq-to-xml xelement
source share
5 answers

You can also try Convert.ChangeType

 Convert.ChangeType(element.Value, typeof(TElementType)) 
+11
source share

From your code, not:

 return (TElementType)((object) element.Value); 

you will do the following:

 return (TElementType) Convert.ChangeType(element.Value, typeof (T)); 

The only caveat here is that TElementType should implement IConvertible. However, if you are just talking about built-in types, they all already implement this.

For your custom types, assuming you want them here, you will need to have your own conversion.

+3
source share

You cannot do an implicit or explicit conversion from String to Int32 , for this you need to use the Int32 Parse or TryParse . Perhaps you could create some useful extension methods, for example:

  using System; using System.Diagnostics; using System.Globalization; using System.Text; /// <summary> /// Provides extension methods for strings. /// </summary> public static class StringExtensions { #region Methods /// <summary> /// Converts the specified string to a <see cref="Boolean"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="Boolean"/>.</returns> public static bool AsBoolean(this string @string) { return bool.Parse(@string); } /// <summary> /// Converts the specified string to a <see cref="Boolean"/> using TryParse. /// </summary> /// <remarks> /// If the specified string cannot be parsed, the default value (if valid) or false is returned. /// </remarks> /// <param name="string">The string to convert.</param> /// <param name="default">The default value for if the value cannot be parsed.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static bool AsBooleanNonStrict(this string @string, bool? @default = null) { bool @bool; if ((!string.IsNullOrEmpty(@string)) && bool.TryParse(@string, out @bool)) return @bool; if (@default.HasValue) return @default.Value; return false; } /// <summary> /// Converts the specified string to a <see cref="DateTime"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static DateTime AsDateTime(this string @string) { return DateTime.Parse(@string); } /// <summary> /// Converts the specified string to a <see cref="DateTime"/> using TryParse. /// </summary> /// <remarks> /// If the specified string cannot be parsed, <see cref="DateTime.MinValue"/> is returned. /// </remarks> /// <param name="string">The string to convert.</param> /// <param name="default">The default value for if the value cannot be parsed.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static DateTime AsDateTimeNonStrict(this string @string, DateTime? @default = null) { DateTime datetime; if ((!string.IsNullOrEmpty(@string)) && DateTime.TryParse(@string, out datetime)) return datetime; if (@default.HasValue) return @default.Value; return DateTime.MinValue; } /// <summary> /// Converts the specified string to a <see cref="TEnum"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="TEnum"/>.</returns> public static TEnum AsEnum<TEnum>(this string @string) where TEnum : struct { return (TEnum)Enum.Parse(typeof(TEnum), @string); } /// <summary> /// Converts the specified string to a <see cref="TEnum"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="TEnum"/>.</returns> public static TEnum AsEnumNonStrict<TEnum>(this string @string, TEnum @default) where TEnum : struct { TEnum @enum; if ((!string.IsNullOrEmpty(@string)) && Enum.TryParse(@string, out @enum)) return @enum; return @default; } /// <summary> /// Converts the specified string to a <see cref="Int32"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="Int32"/>.</returns> public static int AsInteger(this string @string) { return int.Parse(@string); } /// <summary> /// Converts the specified string to a <see cref="Int32"/> using TryParse. /// </summary> /// <remarks> /// If the specified string cannot be parsed, the default value (if valid) or 0 is returned. /// </remarks> /// <param name="string">The string to convert.</param> /// <param name="default">The default value for if the value cannot be parsed.</param> /// <returns>The specified string as a <see cref="Int32"/>.</returns> public static int AsIntegerNonStrict(this string @string, int? @default = null) { int @int; if ((!string.IsNullOrEmpty(@string)) && int.TryParse(@string, out @int)) return @int; if (@default.HasValue) return @default.Value; return 0; } /// <summary> /// Converts the specified string to a <see cref="bool"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static bool? AsNullableBolean(this string @string) { bool @bool; if ((string.IsNullOrEmpty(@string)) || !bool.TryParse(@string, out @bool)) return null; return @bool; } /// <summary> /// Converts the specified string to a <see cref="DateTime"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static DateTime? AsNullableDateTime(this string @string) { DateTime dateTime; if ((string.IsNullOrEmpty(@string)) || !DateTime.TryParse(@string, out dateTime)) return null; return dateTime; } /// <summary> /// Converts the specified string to a <see cref="DateTime"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="DateTime"/>.</returns> public static TEnum? AsNullableEnum<TEnum>(this string @string) where TEnum : struct { TEnum @enum; if ((string.IsNullOrEmpty(@string)) || !Enum.TryParse(@string, out @enum)) return null; return @enum; } /// <summary> /// Converts the specified string to a <see cref="Int32"/> /// </summary> /// <param name="string">The string to convert.</param> /// <returns>The specified string as a <see cref="Int32"/>.</returns> public static int? AsNullableInteger(this string @string) { int @int; if ((string.IsNullOrEmpty(@string)) || !int.TryParse(@string, out @int)) return null; return @int; } #endregion } 

I usually use them quite often.

+2
source share

In C #, you cannot use a string object for Int32. For example, this code generates a compilation error:

  string a = "123.4"; int x = (int) a; 

Try using Convert Class or Int32.Parse and Int32.TryParse if you want this functionality.
And yes, you have to handle numerical casting separately if you want to pass a string to int.

+1
source share
Line

also implements IConvertible, so you can do the following.

 ((IConvertible)mystring).ToInt32(null); 

You can even throw some extension methods around it to make it cleaner.

0
source share

All Articles