generic type conversion in C# - c#

Is there any way the following code can be improved. I'm aware of the non nullable reference in C# 8.0 and was thinking either that or any other way they code below could be made more robust and better in general.
This method is called for converting xml data before insertion in a database Through entity framework core. Any way these tools can be used to improve this code is welcomed.
public object Convert(string value, Type toType)
{
try
{
if (toType == typeof(short))
{
return short.Parse(value);
}
if (toType == typeof(short?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return short.Parse(value);
}
if (toType == typeof(int))
{
return int.Parse(value);
}
if (toType == typeof(int?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return int.Parse(value);
}
if (toType == typeof(decimal))
{
return decimal.Parse(value);
}
if (toType == typeof(decimal?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return decimal.Parse(value);
}
if (toType == typeof(DateTime))
{
return DateTime.Parse(value);
}
if (toType == typeof(DateTime?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return DateTime.Parse(value);
}
throw new NotSupportedException($"No conversion defined for type:'{toType}'");
}
catch (System.FormatException excp)
{
throw new ConversionException($"Value:'{value}' could not be converted to:'{toType.Name}'", excp);
}
}
Many thanks in advance

The only thing I can offer is to improve robustness by using .TryParse() for the parsing instead of .Parse()
class Program
{
static void Main(string[] args)
{
var i = Parse<int>("100");
var x = Parse<double>("3.1417");
var s = Parse<string>("John");
var d = Parse<Decimal>("1234.56");
var f = Parse<DateTime>("4/1/2044");
var q = Parse<byte>("4A");
Decimal? p = Parse<decimal>("Not Decimal");
}
public static dynamic Parse<T>(string text)
{
var toType = typeof(T);
if (toType == typeof(int))
{
if (int.TryParse(text, out int x))
{
return x;
}
}
else if (toType == typeof(short))
{
if (short.TryParse(text, out short x))
{
return x;
}
}
else if (toType == typeof(double))
{
if (double.TryParse(text, out double x))
{
return x;
}
}
else if (toType == typeof(decimal))
{
if (decimal.TryParse(text, out decimal x))
{
return x;
}
}
else if (toType == typeof(DateTime))
{
if (DateTime.TryParse(text, out DateTime x))
{
return x;
}
}
else if (toType == typeof(byte))
{
if (byte.TryParse(text, System.Globalization.NumberStyles.HexNumber, null, out byte x))
{
return x;
}
}
else if (toType == typeof(string))
{
return text;
}
return null;
}
}

IMO the main improvement here would be to remove all boxing. Which means using generics throughout. Now, there's a complication there: with generics, it is hard to change types without with boxing (to convince the compiler you know what you're doing), or using meta-programming. So: I'd lean towards the latter. Something like:
public static T Convert<T>(string input)
=> TypeCache<T>.Convert(input);
private static TypeCache<T> {
public static readonly Func<string, T> Convert
= CreateConverter<T>();
}
private static Func<string, T> CreateConverter<T>()
{...}
The magic all happens in that last method. The problem is: it isn't trivial. The simplest approach should be to use reflection to discover a suitable parse method, then manually construct an Expression<Func<string, T>> by linking appropriate Expression nodes to repreresent the operation, then call Compile() to get a delegate. Another approach is to go straight to DynamicMethod and ILGenerator. Both are advanced topics.

This is the code I wrote and used in my company's project really well.
You can try to use this:
/// <summary>
/// Method : Simply Universal Type Converter
/// Requirement : C# 7.0+
/// Created by : Byungho Park(Tapegawui) in South Korea.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="val">Original value</param>
/// <param name="rfrom">(Optional)Character(s) want to replace from</param>
/// <param name="rto">(Optional)Character(s) will be replace to</param>
/// <returns></returns>
public static T Cast<T>(dynamic val, string rfrom = "", string rto = "") where T : IConvertible
{
try
{
// Convert null to empty else 0
if (val is null || val.Equals(DBNull.Value))
{
if (typeof(T) == typeof(string) || typeof(T) == typeof(DateTime))
{
val = string.Empty;
}
else if (typeof(T) == typeof(bool))
{
val = false;
}
else
{
val = 0;
}
}
else
{
// Replace string given parameter from a to b
if (typeof(T) == typeof(string) && rfrom == "" & rto.Length > 0)
{
if (val.ToString().Length == 0)
{
val = rto;
}
}
else if (typeof(T) == typeof(string) && rto.Length > 0)
{
val = (string)val.ToString().Replace(rfrom, rto);
}
}
// Convert type on this block finally
return (T)Convert.ChangeType(val, typeof(T));
}
catch (Exception)
{
return default(T);
}
}
And usage examples:
using System;
int vint = 10;
int vint2 = vint;
string vstr = "1000000";
string vdcm = "123456789123456789";
for (int i = 1; i <= vint; i++)
{
vint2 += i;
}
Console.WriteLine($"Adding int with loop : {vint2} from {vint}\n");
string tint = Cast<string>(vint);
for (int i = 1; i <= vint; i++)
{
tint += i;
}
Console.WriteLine($"Adding string with loop : {tint} from {vint}\n");
long tlong = Cast<long>(vstr);
tlong *= tlong;
Console.WriteLine($"Multiply long : {tlong} from {vstr}\n");
double tdbl = Cast<double>(vdcm);
for (int i = 1; i <= vint; i++)
{
tdbl *= i;
}
Console.WriteLine($"Multiply double with loop : {tdbl} from {vdcm}\n");
decimal tdcm = Cast<decimal>(vdcm);
for (int i = 1; i <= vint; i++)
{
tdcm *= i;
}
Console.WriteLine($"Multiply decimal with loop : {tdcm} from {vdcm}\n");
string ns = null;
Console.WriteLine($"Null string : {Cast<string>(ns)}\n");
int? ni = null;
Console.WriteLine($"Null int : {Cast<int>(ni)}\n");
long? nl = null;
Console.WriteLine($"Null long : {Cast<long>(nl)}\n");
double? ndbl = null;
Console.WriteLine($"Null double : {Cast<double>(ndbl)}\n");
decimal? nd = null;
Console.WriteLine($"Null decimal : {Cast<decimal>(nd)}\n");
string tb = "true";
Console.WriteLine($"Convert string to boolean : {Cast<bool>(tb)}\n");
bool? nb = null;
Console.WriteLine($"Null boolean : {Cast<bool>(nb)}\n");
// -----------------------
// From Microsoft examples
double d = -2.345;
int t = Cast<int>(d);
Console.WriteLine($"The double value {d} when converted to an int becomes {t}\n");
string s = "98/12/12";
DateTime dt = Cast<DateTime>(s);
Console.WriteLine($"The string value {s} when converted to a Date becomes {dt}\n");
// -----------------------
// ------------------------------------------
// Replace some character(s) with string type
string rs = "Replace this string with x to y.";
Console.WriteLine($"{Cast<string>(rs, " ", "_")}\n");
Console.WriteLine($"{Cast<string>("abcd", "", "abc")}\n");
Console.WriteLine($"{Cast<string>("", "", "abc")}\n");
string rs3 = "Replace this string from x to y.";
string ts = "string";
Console.WriteLine($"{Cast<string>(rs3, ts, ts.ToUpper())}\n");
Console.WriteLine($"Replace int character with string : {Cast<string>(vstr, "0", "1")}\n");
// ------------------------------------------
Console.WriteLine("Press any key to close...");
Console.ReadKey();
In addition, output results:
Adding int with loop : 65 from 10
Adding string with loop : 1012345678910 from 10
Multiply long : 1000000000000 from 1000000
Multiply double with loop : 4.479999963712E+23 from 123456789123456789
Multiply decimal with loop : 447999996371199995923200 from 123456789123456789
Null string :
Null int : 0
Null long : 0
Null double : 0
Null decimal : 0
Convert string to boolean : True
Null boolean : False
The double value -2.345 when converted to an int becomes -2
The string value 98/12/12 when converted to a Date becomes 1998-12-12 오전 12:00:00
Replace_this_string_with_x_to_y.
abcd
abc
Replace this STRING from x to y.
Replace int character with string : 1111111
Press any key to close...

public static class StringExtensions
{
public static TDest ConvertStringTo<TDest>(this string src)
{
if (src == null)
{
return default(TDest);
}
try
{
return ChangeType<TDest>(src);
}
catch
{
return default(TDest);
}
}
private static T ChangeType<T>(string value)
{
var t = typeof(T);
if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
t = Nullable.GetUnderlyingType(t);
}
return (T)Convert.ChangeType(value, t);
}
}

Using runtime infrastructure to determine types and perform conversions between them as proposed by the other answers is very convenient and probably what you are looking for.
If, however, you need more control over your conversion (or rather parsing), e.g. because you get weird input formats that require pre-processing, may I suggest the following class.
It lets you provide a parser method for each type you register. The types from your question with their nullable cousins come pre-registered in the constructor, but you can also add any other method to the dictionary as your input data requires:
public delegate bool Parser<T>(string input, out T output);
public class Parsers
{
private delegate bool UntypedParser(string input, out object output);
private Dictionary<Type, UntypedParser> _parsersByType = new Dictionary<Type, UntypedParser>();
/// <summary>
/// Creates a <see cref="Parsers"/> instance pre-populated with parsers for the most common types.
/// </summary>
public static Parsers CreateDefault()
{
Parsers result = new Parsers();
result.AddParser<string>((string input, out string output) => { output = input; return true; });
result.AddParserForNullable<bool>(bool.TryParse);
result.AddParserForNullable<byte>(byte.TryParse);
result.AddParserForNullable<DateTime>(DateTime.TryParse);
result.AddParserForNullable<decimal>(decimal.TryParse);
result.AddParserForNullable<double>(double.TryParse);
result.AddParserForNullable<float>(float.TryParse);
result.AddParserForNullable<int>(int.TryParse);
result.AddParserForNullable<short>(short.TryParse);
return result;
}
/// <summary>
/// Registers a parser for the given type T
/// </summary>
public void AddParser<T>(Parser<T> parser)
{
_parsersByType[typeof(T)] = (string input, out object output) => ParseObject(parser, input, out output);
}
/// <summary>
/// Registers a parser for the given type T as well as <see cref="Nullable{T}"/>
/// </summary>
public void AddParserForNullable<T>(Parser<T> parser)
where T : struct
{
_parsersByType[typeof(T)] = (string input, out object output) => ParseObject(parser, input, out output);
_parsersByType[typeof(T?)] = (string input, out object output) => ParseNullable(parser, input, out output);
}
/// <summary>
/// For nullable types, return null when the input is an empty string or null.
/// </summary>
/// <remarks>This is not called for the string-parser. Meaning an empty string is not parsed into a null value.</remarks>
private bool ParseNullable<T>(Parser<T> parser, string input, out object output)
where T : struct
{
bool result;
if (string.IsNullOrEmpty(input))
{
result = true;
output = null;
}
else
{
result = ParseObject(parser, input, out output);
}
return result;
}
/// <summary>
/// Helper method to convert the typed output into an object (possibly boxing the value)
/// </summary>
private bool ParseObject<T>(Parser<T> parser, string input, out object output)
{
bool result = parser(input, out T typedOutput);
output = typedOutput;
return result;
}
/// <summary>
/// Finds the parser for the given target type and uses it to parse the input.
/// </summary>
public object Parse<T>(string input)
{
Type targetType = typeof(T);
object result;
if (!_parsersByType.TryGetValue(targetType, out UntypedParser parser))
{
throw new ArgumentException($"No parser defined for type '{targetType}'.");
}
else if (!parser(input, out result))
{
throw new ArgumentException($"Cannot parse '{targetType}' from input '{input}'.");
}
return result;
}
}

Related

Get the type name

How i can get full right name of generic type?
For example:
This code
typeof(List<string>).Name
return
List`1
instead of
List<string>
How to get a right name?
typeof(List<string>).ToString()
returns System.Collections.Generic.List`1[System.String] but i want to get initial name:
List<string>
Is it real?
Use the FullName property.
typeof(List<string>).FullName
That will give you the namespace + class + type parameters.
What you are asking for is a C# specific syntax. As far as .NET is concerned, this is proper:
System.Collections.Generic.List`1[System.String]
So to get what you want, you'd have to write a function to build it the way you want it. Perhaps like so:
static string GetCSharpRepresentation( Type t, bool trimArgCount ) {
if( t.IsGenericType ) {
var genericArgs = t.GetGenericArguments().ToList();
return GetCSharpRepresentation( t, trimArgCount, genericArgs );
}
return t.Name;
}
static string GetCSharpRepresentation( Type t, bool trimArgCount, List<Type> availableArguments ) {
if( t.IsGenericType ) {
string value = t.Name;
if( trimArgCount && value.IndexOf("`") > -1 ) {
value = value.Substring( 0, value.IndexOf( "`" ) );
}
if( t.DeclaringType != null ) {
// This is a nested type, build the nesting type first
value = GetCSharpRepresentation( t.DeclaringType, trimArgCount, availableArguments ) + "+" + value;
}
// Build the type arguments (if any)
string argString = "";
var thisTypeArgs = t.GetGenericArguments();
for( int i = 0; i < thisTypeArgs.Length && availableArguments.Count > 0; i++ ) {
if( i != 0 ) argString += ", ";
argString += GetCSharpRepresentation( availableArguments[0], trimArgCount );
availableArguments.RemoveAt( 0 );
}
// If there are type arguments, add them with < >
if( argString.Length > 0 ) {
value += "<" + argString + ">";
}
return value;
}
return t.Name;
}
For these types (with true as 2nd param):
typeof( List<string> ) )
typeof( List<Dictionary<int, string>> )
It returns:
List<String>
List<Dictionary<Int32, String>>
In general though, I'd bet you probably don't need to have the C# representation of your code and perhaps if you do, some format better than the C# syntax would be more appropriate.
You could use this:
public static string GetTypeName(Type t) {
if (!t.IsGenericType) return t.Name;
if (t.IsNested && t.DeclaringType.IsGenericType) throw new NotImplementedException();
string txt = t.Name.Substring(0, t.Name.IndexOf('`')) + "<";
int cnt = 0;
foreach (Type arg in t.GetGenericArguments()) {
if (cnt > 0) txt += ", ";
txt += GetTypeName(arg);
cnt++;
}
return txt + ">";
}
For example:
static void Main(string[] args) {
var obj = new Dictionary<string, Dictionary<HashSet<int>, int>>();
string s = GetTypeName(obj.GetType());
Console.WriteLine(s);
Console.ReadLine();
}
Output:
Dictionary<String, Dictionary<HashSet<Int32>, Int32>>
If you have an instance of the list, you can call .ToString() and get the following
System.Collections.Generic.List`1[System.String]
This is in addition to the methods provided by the other answers directly against the type rather than the instance.
Edit: On your edit, I do not believe it is possible without providing your own parsing method, as List<string> is C# shorthand for how the type is implemented, sort of like if you wrote typeof(int).ToString(), what is captured is not "int" but the CTS name, System.Int32.
Here's my implementation, which benefited from #Hans's answer above and #Jack's answer on a duplicate question.
public static string GetCSharpName( this Type type )
{
string result;
if ( primitiveTypes.TryGetValue( type, out result ) )
return result;
else
result = type.Name.Replace( '+', '.' );
if ( !type.IsGenericType )
return result;
else if ( type.IsNested && type.DeclaringType.IsGenericType )
throw new NotImplementedException();
result = result.Substring( 0, result.IndexOf( "`" ) );
return result + "<" + string.Join( ", ", type.GetGenericArguments().Select( GetCSharpName ) ) + ">";
}
static Dictionary<Type, string> primitiveTypes = new Dictionary<Type, string>
{
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(float), "float" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(string), "string" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
{ typeof(ushort), "ushort" },
};
Another way to get a nice type name by using an extension:
typeof(Dictionary<string, Dictionary<decimal, List<int>>>).CSharpName();
// output is:
// Dictionary<String, Dictionary<Decimal, List<Int32>>>
The Extension Code:
public static class TypeExtensions
{
public static string CSharpName(this Type type)
{
string typeName = type.Name;
if (type.IsGenericType)
{
var genArgs = type.GetGenericArguments();
if (genArgs.Count() > 0)
{
typeName = typeName.Substring(0, typeName.Length - 2);
string args = "";
foreach (var argType in genArgs)
{
string argName = argType.Name;
if (argType.IsGenericType)
argName = argType.CSharpName();
args += argName + ", ";
}
typeName = string.Format("{0}<{1}>", typeName, args.Substring(0, args.Length - 2));
}
}
return typeName;
}
}
typeof(List<string>).ToString()
An improvement on Adam Sills's answer that works with non-generic nested types, and generic type definitions:
public class TypeNameStringExtensions
{
public static string GetCSharpRepresentation(Type t)
{
return GetCSharpRepresentation(t, new Queue<Type>(t.GetGenericArguments()));
}
static string GetCSharpRepresentation(Type t, Queue<Type> availableArguments)
{
string value = t.Name;
if (t.IsGenericParameter)
{
return value;
}
if (t.DeclaringType != null)
{
// This is a nested type, build the parent type first
value = GetCSharpRepresentation(t.DeclaringType, availableArguments) + "+" + value;
}
if (t.IsGenericType)
{
value = value.Split('`')[0];
// Build the type arguments (if any)
string argString = "";
var thisTypeArgs = t.GetGenericArguments();
for (int i = 0; i < thisTypeArgs.Length && availableArguments.Count > 0; i++)
{
if (i != 0) argString += ", ";
argString += GetCSharpRepresentation(availableArguments.Dequeue());
}
// If there are type arguments, add them with < >
if (argString.Length > 0)
{
value += "<" + argString + ">";
}
}
return value;
}
[TestCase(typeof(List<string>), "List<String>")]
[TestCase(typeof(List<Dictionary<int, string>>), "List<Dictionary<Int32, String>>")]
[TestCase(typeof(Stupid<int>.Stupider<int>), "Stupid<Int32>+Stupider<Int32>")]
[TestCase(typeof(Dictionary<int, string>.KeyCollection), "Dictionary<Int32, String>+KeyCollection")]
[TestCase(typeof(Nullable<Point>), "Nullable<Point>")]
[TestCase(typeof(Point?), "Nullable<Point>")]
[TestCase(typeof(TypeNameStringExtensions), "TypeNameStringExtensions")]
[TestCase(typeof(Another), "TypeNameStringExtensions+Another")]
[TestCase(typeof(G<>), "TypeNameStringExtensions+G<T>")]
[TestCase(typeof(G<string>), "TypeNameStringExtensions+G<String>")]
[TestCase(typeof(G<Another>), "TypeNameStringExtensions+G<TypeNameStringExtensions+Another>")]
[TestCase(typeof(H<,>), "TypeNameStringExtensions+H<T1, T2>")]
[TestCase(typeof(H<string, Another>), "TypeNameStringExtensions+H<String, TypeNameStringExtensions+Another>")]
[TestCase(typeof(Another.I<>), "TypeNameStringExtensions+Another+I<T3>")]
[TestCase(typeof(Another.I<int>), "TypeNameStringExtensions+Another+I<Int32>")]
[TestCase(typeof(G<>.Nested), "TypeNameStringExtensions+G<T>+Nested")]
[TestCase(typeof(G<string>.Nested), "TypeNameStringExtensions+G<String>+Nested")]
[TestCase(typeof(A<>.C<>), "TypeNameStringExtensions+A<B>+C<D>")]
[TestCase(typeof(A<int>.C<string>), "TypeNameStringExtensions+A<Int32>+C<String>")]
public void GetCSharpRepresentation_matches(Type type, string expected)
{
string actual = GetCSharpRepresentation(type);
Assert.AreEqual(expected, actual);
}
public class G<T>
{
public class Nested { }
}
public class A<B>
{
public class C<D> { }
}
public class H<T1, T2> { }
public class Another
{
public class I<T3> { }
}
}
public class Stupid<T1>
{
public class Stupider<T2>
{
}
}
I also chose to forgo his trimArgCount, as I can't see when that would be useful, and to use a Queue<Type> since that was the intent (pulling items off the front while they exist).
I had problems with the other answers in some instances, i.e. with arrays, so I ended up writing yet another one. I don't use the text from Type.Name or similar except to get the plain name of the types, because I don't know if the format is guaranteed to be the same across different .Net versions or with other implementations of the libraries (I assume it isn't).
/// <summary>
/// For the given type, returns its representation in C# code.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="genericArgs">Used internally, ignore.</param>
/// <param name="arrayBrackets">Used internally, ignore.</param>
/// <returns>The representation of the type in C# code.</returns>
public static string GetTypeCSharpRepresentation(Type type, Stack<Type> genericArgs = null, StringBuilder arrayBrackets = null)
{
StringBuilder code = new StringBuilder();
Type declaringType = type.DeclaringType;
bool arrayBracketsWasNull = arrayBrackets == null;
if (genericArgs == null)
genericArgs = new Stack<Type>(type.GetGenericArguments());
int currentTypeGenericArgsCount = genericArgs.Count;
if (declaringType != null)
currentTypeGenericArgsCount -= declaringType.GetGenericArguments().Length;
Type[] currentTypeGenericArgs = new Type[currentTypeGenericArgsCount];
for (int i = currentTypeGenericArgsCount - 1; i >= 0; i--)
currentTypeGenericArgs[i] = genericArgs.Pop();
if (declaringType != null)
code.Append(GetTypeCSharpRepresentation(declaringType, genericArgs)).Append('.');
if (type.IsArray)
{
if (arrayBrackets == null)
arrayBrackets = new StringBuilder();
arrayBrackets.Append('[');
arrayBrackets.Append(',', type.GetArrayRank() - 1);
arrayBrackets.Append(']');
Type elementType = type.GetElementType();
code.Insert(0, GetTypeCSharpRepresentation(elementType, arrayBrackets : arrayBrackets));
}
else
{
code.Append(new string(type.Name.TakeWhile(c => char.IsLetterOrDigit(c) || c == '_').ToArray()));
if (currentTypeGenericArgsCount > 0)
{
code.Append('<');
for (int i = 0; i < currentTypeGenericArgsCount; i++)
{
code.Append(GetTypeCSharpRepresentation(currentTypeGenericArgs[i]));
if (i < currentTypeGenericArgsCount - 1)
code.Append(',');
}
code.Append('>');
}
if (declaringType == null && !string.IsNullOrEmpty(type.Namespace))
{
code.Insert(0, '.').Insert(0, type.Namespace);
}
}
if (arrayBracketsWasNull && arrayBrackets != null)
code.Append(arrayBrackets.ToString());
return code.ToString();
}
I have tested it with crazy types like this, and so far it has worked perfectly:
class C
{
public class D<D1, D2>
{
public class E
{
public class K<R1, R2, R3>
{
public class P<P1>
{
public struct Q
{
}
}
}
}
}
}
type = typeof(List<Dictionary<string[], C.D<byte, short[,]>.E.K<List<int>[,][], Action<List<long[][][,]>[], double[][,]>, float>.P<string>.Q>>[][,][,,,][][,,]);
// Returns "System.Collections.Generic.List<System.Collections.Generic.Dictionary<System.String[],Test.Program.C.D<System.Byte,System.Int16[,]>.E.K<System.Collections.Generic.List<System.Int32>[,][],System.Action<System.Collections.Generic.List<System.Int64[][][,]>[],System.Double[][,]>,System.Single>.P<System.String>.Q>>[][,][,,,][][,,]":
GetTypeCSharpRepresentation(type);
There may still be some gotchas I didn't think about, but there's a known one: to retrieve the names, I only get characters that meet the condition char.IsLetterOrDigit(c) || c == '_' until one that doesn't is found, so any names of types that use allowed characters that don't meet the condition will fail.
Came across this and thought I'd share my own solution. It handles multiple generic arguments, nullables, jagged arrays, multidimensional arrays, combinations of jagged/multidimensional arrays, and any nesting combinations of any of the above. I use it mainly for logging so that it's easier to identify complicated types.
public static string GetGoodName(this Type type)
{
var sb = new StringBuilder();
void VisitType(Type inType)
{
if (inType.IsArray)
{
var rankDeclarations = new Queue<string>();
Type elType = inType;
do
{
rankDeclarations.Enqueue($"[{new string(',', elType.GetArrayRank() - 1)}]");
elType = elType.GetElementType();
} while (elType.IsArray);
VisitType(elType);
while (rankDeclarations.Count > 0)
{
sb.Append(rankDeclarations.Dequeue());
}
}
else
{
if (inType.IsGenericType)
{
var isNullable = inType.IsNullable();
var genargs = inType.GetGenericArguments().AsEnumerable();
var numer = genargs.GetEnumerator();
numer.MoveNext();
if (!isNullable) sb.Append($"{inType.Name.Substring(0, inType.Name.IndexOf('`'))}<");
VisitType(numer.Current);
while (numer.MoveNext())
{
sb.Append(",");
VisitType(numer.Current);
}
if (isNullable)
{
sb.Append("?");
}
else
{
sb.Append(">");
}
}
else
{
sb.Append(inType.Name);
}
}
}
VisitType(type);
var s = sb.ToString();
return s;
}
This:
typeof(Dictionary<int?, Tuple<string[], List<string[][,,,]>>>).GetGoodName()
...returns this:
Dictionary<Int32?,Tuple<String[],List<String[][,,,]>>>
If you want the base generic type used:
List<string> lstString = new List<string>();
Type type = lstString.GetType().GetGenericTypeDefinition();
Assuming that you want to use the type do do something and that you don't really need the actual string definition which isn't all that useful.

What are your favorite custom extension methods? [duplicate]

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Let's make a list of answers where you post your excellent and favorite extension methods.
The requirement is that the full code must be posted and a example and an explanation on how to use it.
Based on the high interest in this topic I have setup an Open Source Project called extensionoverflow on Codeplex.
Please mark your answers with an acceptance to put the code in the Codeplex project.
Please post the full sourcecode and not a link.
Codeplex News:
24.08.2010 The Codeplex page is now here: http://extensionoverflow.codeplex.com/
11.11.2008 XmlSerialize / XmlDeserialize is now Implemented and Unit Tested.
11.11.2008 There is still room for more developers. ;-) Join NOW!
11.11.2008 Third contributer joined ExtensionOverflow, welcome to BKristensen
11.11.2008 FormatWith is now Implemented and Unit Tested.
09.11.2008 Second contributer joined ExtensionOverflow. welcome to chakrit.
09.11.2008 We need more developers. ;-)
09.11.2008 ThrowIfArgumentIsNull in now Implemented and Unit Tested on Codeplex.
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Allows me to replace:
if(reallyLongIntegerVariableName == 1 ||
reallyLongIntegerVariableName == 6 ||
reallyLongIntegerVariableName == 9 ||
reallyLongIntegerVariableName == 11)
{
// do something....
}
and
if(reallyLongStringVariableName == "string1" ||
reallyLongStringVariableName == "string2" ||
reallyLongStringVariableName == "string3")
{
// do something....
}
and
if(reallyLongMethodParameterName == SomeEnum.Value1 ||
reallyLongMethodParameterName == SomeEnum.Value2 ||
reallyLongMethodParameterName == SomeEnum.Value3 ||
reallyLongMethodParameterName == SomeEnum.Value4)
{
// do something....
}
With:
if(reallyLongIntegerVariableName.In(1,6,9,11))
{
// do something....
}
and
if(reallyLongStringVariableName.In("string1","string2","string3"))
{
// do something....
}
and
if(reallyLongMethodParameterName.In(SomeEnum.Value1, SomeEnum.Value2, SomeEnum.Value3, SomeEnum.Value4)
{
// do something....
}
I have various extension methods in my MiscUtil project (full source is available there - I'm not going to repeat it here). My favourites, some of which involve other classes (such as ranges):
Date and time stuff - mostly for unit tests. Not sure I'd use them in production :)
var birthday = 19.June(1976);
var workingDay = 7.Hours() + 30.Minutes();
Ranges and stepping - massive thanks to Marc Gravell for his operator stuff to make this possible:
var evenNaturals = 2.To(int.MaxValue).Step(2);
var daysSinceBirth = birthday.To(DateTime.Today).Step(1.Days());
Comparisons:
var myComparer = ProjectionComparer.Create(Person p => p.Name);
var next = myComparer.ThenBy(p => p.Age);
var reversed = myComparer.Reverse();
Argument checking:
x.ThrowIfNull("x");
LINQ to XML applied to anonymous types (or other types with appropriate properties):
// <Name>Jon</Name><Age>32</Age>
new { Name="Jon", Age=32}.ToXElements();
// Name="Jon" Age="32" (as XAttributes, obviously)
new { Name="Jon", Age=32}.ToXAttributes()
Push LINQ - would take too long to explain here, but search for it.
string.Format shortcut:
public static class StringExtensions
{
// Enable quick and more natural string.Format calls
public static string F(this string s, params object[] args)
{
return string.Format(s, args);
}
}
Example:
var s = "The co-ordinate is ({0}, {1})".F(point.X, point.Y);
For quick copy-and-paste go here.
Don't you find it more natural to type "some string".F("param") instead of string.Format("some string", "param") ?
For a more readable name, try one of these suggestion:
s = "Hello {0} world {1}!".Fmt("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatBy("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatWith("Stack", "Overflow");
s = "Hello {0} world {1}!".Display("Stack", "Overflow");
s = "Hello {0} world {1}!".With("Stack", "Overflow");
..
Are these any use?
public static bool CoinToss(this Random rng)
{
return rng.Next(2) == 0;
}
public static T OneOf<T>(this Random rng, params T[] things)
{
return things[rng.Next(things.Length)];
}
Random rand;
bool luckyDay = rand.CoinToss();
string babyName = rand.OneOf("John", "George", "Radio XBR74 ROCKS!");
public static class ComparableExtensions
{
public static bool Between<T>(this T actual, T lower, T upper) where T : IComparable<T>
{
return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) < 0;
}
}
Example:
if (myNumber.Between(3,7))
{
// ....
}
The extension method:
public static void AddRange<T, S>(this ICollection<T> list, params S[] values)
where S : T
{
foreach (S value in values)
list.Add(value);
}
The method applies for all types and lets you add a range of items to a list as parameters.
Example:
var list = new List<Int32>();
list.AddRange(5, 4, 8, 4, 2);
By all means put this in the codeplex project.
Serializing / Deserializing objects to XML:
/// <summary>Serializes an object of type T in to an xml string</summary>
/// <typeparam name="T">Any class type</typeparam>
/// <param name="obj">Object to serialize</param>
/// <returns>A string that represents Xml, empty otherwise</returns>
public static string XmlSerialize<T>(this T obj) where T : class, new()
{
if (obj == null) throw new ArgumentNullException("obj");
var serializer = new XmlSerializer(typeof(T));
using (var writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
/// <summary>Deserializes an xml string in to an object of Type T</summary>
/// <typeparam name="T">Any class type</typeparam>
/// <param name="xml">Xml as string to deserialize from</param>
/// <returns>A new object of type T is successful, null if failed</returns>
public static T XmlDeserialize<T>(this string xml) where T : class, new()
{
if (xml == null) throw new ArgumentNullException("xml");
var serializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(xml))
{
try { return (T)serializer.Deserialize(reader); }
catch { return null; } // Could not be deserialized to this type.
}
}
ForEach for IEnumerables
public static class FrameworkExtensions
{
// a map function
public static void ForEach<T>(this IEnumerable<T> #enum, Action<T> mapFunction)
{
foreach (var item in #enum) mapFunction(item);
}
}
Naive example:
var buttons = GetListOfButtons() as IEnumerable<Button>;
// click all buttons
buttons.ForEach(b => b.Click());
Cool example:
// no need to type the same assignment 3 times, just
// new[] up an array and use foreach + lambda
// everything is properly inferred by csc :-)
new { itemA, itemB, itemC }
.ForEach(item => {
item.Number = 1;
item.Str = "Hello World!";
});
Note:
This is not like Select because Select expects your function to return something as for transforming into another list.
ForEach simply allows you to execute something for each of the items without any transformations/data manipulation.
I made this so I can program in a more functional style and I was surprised that List has a ForEach while IEnumerable does not.
Put this in the codeplex project
My conversion extensions which allow you to do:
int i = myString.To<int>();
Here it is, as posted on TheSoftwareJedi.com
public static T To<T>(this IConvertible obj)
{
return (T)Convert.ChangeType(obj, typeof(T));
}
public static T ToOrDefault<T>
(this IConvertible obj)
{
try
{
return To<T>(obj);
}
catch
{
return default(T);
}
}
public static bool ToOrDefault<T>
(this IConvertible obj,
out T newObj)
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = default(T);
return false;
}
}
public static T ToOrOther<T>
(this IConvertible obj,
T other)
{
try
{
return To<T>obj);
}
catch
{
return other;
}
}
public static bool ToOrOther<T>
(this IConvertible obj,
out T newObj,
T other)
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = other;
return false;
}
}
public static T ToOrNull<T>
(this IConvertible obj)
where T : class
{
try
{
return To<T>(obj);
}
catch
{
return null;
}
}
public static bool ToOrNull<T>
(this IConvertible obj,
out T newObj)
where T : class
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = null;
return false;
}
}
You can ask for default (calls blank constructor or "0" for numerics) on failure, specify a "default" value (I call it "other"), or ask for null (where T : class). I've also provided both silent exception models, and a typical TryParse model that returns a bool indicating the action taken, and an out param holds the new value.
So our code can do things like this
int i = myString.To<int>();
string a = myInt.ToOrDefault<string>();
//note type inference
DateTime d = myString.ToOrOther(DateTime.MAX_VALUE);
double d;
//note type inference
bool didItGiveDefault = myString.ToOrDefault(out d);
string s = myDateTime.ToOrNull<string>();
I couldn't get Nullable types to roll into the whole thing very cleanly. I tried for about 20 minutes before I threw in the towel.
I have an extension method for logging exceptions:
public static void Log(this Exception obj)
{
//your logging logic here
}
And it is used like this:
try
{
//Your stuff here
}
catch(Exception ex)
{
ex.Log();
}
[sorry for posting twice; the 2nd one is better designed :-)]
public static class StringExtensions {
/// <summary>
/// Parses a string into an Enum
/// </summary>
/// <typeparam name="T">The type of the Enum</typeparam>
/// <param name="value">String value to parse</param>
/// <returns>The Enum corresponding to the stringExtensions</returns>
public static T EnumParse<T>(this string value) {
return StringExtensions.EnumParse<T>(value, false);
}
public static T EnumParse<T>(this string value, bool ignorecase) {
if (value == null) {
throw new ArgumentNullException("value");
}
value = value.Trim();
if (value.Length == 0) {
throw new ArgumentException("Must specify valid information for parsing in the string.", "value");
}
Type t = typeof(T);
if (!t.IsEnum) {
throw new ArgumentException("Type provided must be an Enum.", "T");
}
return (T)Enum.Parse(t, value, ignorecase);
}
}
Useful to parse a string into an Enum.
public enum TestEnum
{
Bar,
Test
}
public class Test
{
public void Test()
{
TestEnum foo = "Test".EnumParse<TestEnum>();
}
}
Credit goes to Scott Dorman
--- Edit for Codeplex project ---
I have asked Scott Dorman if he would mind us publishing his code in the Codeplex project. This is the reply I got from him:
Thanks for the heads-up on both the SO post and the CodePlex project. I have upvoted your answer on the question. Yes, the code is effectively in the public domain currently under the CodeProject Open License (http://www.codeproject.com/info/cpol10.aspx).
I have no problems with this being included in the CodePlex project, and if you want to add me to the project (username is sdorman) I will add that method plus some additional enum helper methods.
I find this one pretty useful:
public static class PaulaBean
{
private static String paula = "Brillant";
public static String GetPaula<T>(this T obj) {
return paula;
}
}
You may use it on CodePlex.
DateTimeExtensions
Examples:
DateTime firstDayOfMonth = DateTime.Now.First();
DateTime lastdayOfMonth = DateTime.Now.Last();
DateTime lastFridayInMonth = DateTime.Now.Last(DayOfWeek.Friday);
DateTime nextFriday = DateTime.Now.Next(DayOfWeek.Friday);
DateTime lunchTime = DateTime.Now.SetTime(11, 30);
DateTime noonOnFriday = DateTime.Now.Next(DayOfWeek.Friday).Noon();
DateTime secondMondayOfMonth = DateTime.Now.First(DayOfWeek.Monday).Next(DayOfWeek.Monday).Midnight();
gitorious.org/cadenza is a full library of some of the most useful extension methods I've seen.
Here is one I use frequently for presentation formatting.
public static string ToTitleCase(this string mText)
{
if (mText == null) return mText;
System.Globalization.CultureInfo cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Globalization.TextInfo textInfo = cultureInfo.TextInfo;
// TextInfo.ToTitleCase only operates on the string if is all lower case, otherwise it returns the string unchanged.
return textInfo.ToTitleCase(mText.ToLower());
}
Here's a to-and-from for Roman numerals. Not often used, but could be handy. Usage:
if ("IV".IsValidRomanNumeral())
{
// Do useful stuff with the number 4.
}
Console.WriteLine("MMMDCCCLXXXVIII".ParseRomanNumeral());
Console.WriteLine(3888.ToRomanNumeralString());
The source:
public static class RomanNumeralExtensions
{
private const int NumberOfRomanNumeralMaps = 13;
private static readonly Dictionary<string, int> romanNumerals =
new Dictionary<string, int>(NumberOfRomanNumeralMaps)
{
{ "M", 1000 },
{ "CM", 900 },
{ "D", 500 },
{ "CD", 400 },
{ "C", 100 },
{ "XC", 90 },
{ "L", 50 },
{ "XL", 40 },
{ "X", 10 },
{ "IX", 9 },
{ "V", 5 },
{ "IV", 4 },
{ "I", 1 }
};
private static readonly Regex validRomanNumeral = new Regex(
"^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))"
+ "?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$",
RegexOptions.Compiled);
public static bool IsValidRomanNumeral(this string value)
{
return validRomanNumeral.IsMatch(value);
}
public static int ParseRomanNumeral(this string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
value = value.ToUpperInvariant().Trim();
var length = value.Length;
if ((length == 0) || !value.IsValidRomanNumeral())
{
throw new ArgumentException("Empty or invalid Roman numeral string.", "value");
}
var total = 0;
var i = length;
while (i > 0)
{
var digit = romanNumerals[value[--i].ToString()];
if (i > 0)
{
var previousDigit = romanNumerals[value[i - 1].ToString()];
if (previousDigit < digit)
{
digit -= previousDigit;
i--;
}
}
total += digit;
}
return total;
}
public static string ToRomanNumeralString(this int value)
{
const int MinValue = 1;
const int MaxValue = 3999;
if ((value < MinValue) || (value > MaxValue))
{
throw new ArgumentOutOfRangeException("value", value, "Argument out of Roman numeral range.");
}
const int MaxRomanNumeralLength = 15;
var sb = new StringBuilder(MaxRomanNumeralLength);
foreach (var pair in romanNumerals)
{
while (value / pair.Value > 0)
{
sb.Append(pair.Key);
value -= pair.Value;
}
}
return sb.ToString();
}
}
A convenient way to deal with sizes:
public static class Extensions {
public static int K(this int value) {
return value * 1024;
}
public static int M(this int value) {
return value * 1024 * 1024;
}
}
public class Program {
public void Main() {
WSHttpContextBinding serviceMultipleTokenBinding = new WSHttpContextBinding() {
MaxBufferPoolSize = 2.M(), // instead of 2097152
MaxReceivedMessageSize = 64.K(), // instead of 65536
};
}
}
For Winform Controls:
/// <summary>
/// Returns whether the function is being executed during design time in Visual Studio.
/// </summary>
public static bool IsDesignTime(this Control control)
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
return true;
}
if (control.Site != null && control.Site.DesignMode)
{
return true;
}
var parent = control.Parent;
while (parent != null)
{
if (parent.Site != null && parent.Site.DesignMode)
{
return true;
}
parent = parent.Parent;
}
return false;
}
/// <summary>
/// Sets the DropDownWidth to ensure that no item's text is cut off.
/// </summary>
public static void SetDropDownWidth(this ComboBox comboBox)
{
var g = comboBox.CreateGraphics();
var font = comboBox.Font;
float maxWidth = 0;
foreach (var item in comboBox.Items)
{
maxWidth = Math.Max(maxWidth, g.MeasureString(item.ToString(), font).Width);
}
if (comboBox.Items.Count > comboBox.MaxDropDownItems)
{
maxWidth += SystemInformation.VerticalScrollBarWidth;
}
comboBox.DropDownWidth = Math.Max(comboBox.Width, Convert.ToInt32(maxWidth));
}
IsDesignTime Usage:
public class SomeForm : Form
{
public SomeForm()
{
InitializeComponent();
if (this.IsDesignTime())
{
return;
}
// Do something that makes the visual studio crash or hang if we're in design time,
// but any other time executes just fine
}
}
SetDropdownWidth Usage:
ComboBox cbo = new ComboBox { Width = 50 };
cbo.Items.Add("Short");
cbo.Items.Add("A little longer");
cbo.Items.Add("Holy cow, this is a really, really long item. How in the world will it fit?");
cbo.SetDropDownWidth();
I forgot to mention, feel free to use these on Codeplex...
The ThrowIfArgumentIsNull is a nice way to do that null check we all should do.
public static class Extensions
{
public static void ThrowIfArgumentIsNull<T>(this T obj, string parameterName) where T : class
{
if (obj == null) throw new ArgumentNullException(parameterName + " not allowed to be null");
}
}
Below is the way to use it and it works on all classes in your namespace or wherever you use the namespace its within.
internal class Test
{
public Test(string input1)
{
input1.ThrowIfArgumentIsNull("input1");
}
}
It's ok to use this code on the CodePlex project.
I miss the Visual Basic's With statement when moving to C#, so here it goes:
public static void With<T>(this T obj, Action<T> act) { act(obj); }
And here's how to use it in C#:
someVeryVeryLonggggVariableName.With(x => {
x.Int = 123;
x.Str = "Hello";
x.Str2 = " World!";
});
Saves a lot of typing!
Compare this to:
someVeryVeryLonggggVariableName.Int = 123;
someVeryVeryLonggggVariableName.Str = "Hello";
someVeryVeryLonggggVariableName.Str2 = " World!";
put in codeplex project
Takes a camelCaseWord or PascalCaseWord and "wordifies" it, ie camelCaseWord => camel Case Word
public static string Wordify( this string camelCaseWord )
{
// if the word is all upper, just return it
if( !Regex.IsMatch( camelCaseWord, "[a-z]" ) )
return camelCaseWord;
return string.Join( " ", Regex.Split( camelCaseWord, #"(?<!^)(?=[A-Z])" ) );
}
I often use it in conjuction with Capitalize
public static string Capitalize( this string word )
{
return word[0].ToString( ).ToUpper( ) + word.Substring( 1 );
}
Example usage
SomeEntityObject entity = DataAccessObject.GetSomeEntityObject( id );
List<PropertyInfo> properties = entity.GetType().GetPublicNonCollectionProperties( );
// wordify the property names to act as column headers for an html table or something
List<string> columns = properties.Select( p => p.Name.Capitalize( ).Wordify( ) ).ToList( );
Free to use in codeplex project
I found this one helpful
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
return pSeq ?? Enumerable.Empty<T>();
}
It removes the null check in the calling code. You could now do
MyList.EmptyIfNull().Where(....)
Convert a double to string formatted using the specified culture:
public static class ExtensionMethods
{
public static string ToCurrency(this double value, string cultureName)
{
CultureInfo currentCulture = new CultureInfo(cultureName);
return (string.Format(currentCulture, "{0:C}", value));
}
}
Example:
double test = 154.20;
string testString = test.ToCurrency("en-US"); // $154.20
Below is an extension method that adapts Rick Strahl's code (and the comments too) to stop you having to guess or read the byte order mark of a byte array or text file each time you convert it to a string.
The snippet allows you to simply do:
byte[] buffer = File.ReadAllBytes(#"C:\file.txt");
string content = buffer.GetString();
If you find any bugs please add to the comments. Feel free to include it in the Codeplex project.
public static class Extensions
{
/// <summary>
/// Converts a byte array to a string, using its byte order mark to convert it to the right encoding.
/// Original article: http://www.west-wind.com/WebLog/posts/197245.aspx
/// </summary>
/// <param name="buffer">An array of bytes to convert</param>
/// <returns>The byte as a string.</returns>
public static string GetString(this byte[] buffer)
{
if (buffer == null || buffer.Length == 0)
return "";
// Ansi as default
Encoding encoding = Encoding.Default;
/*
EF BB BF UTF-8
FF FE UTF-16 little endian
FE FF UTF-16 big endian
FF FE 00 00 UTF-32, little endian
00 00 FE FF UTF-32, big-endian
*/
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
encoding = Encoding.UTF8;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
encoding = Encoding.Unicode;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
encoding = Encoding.BigEndianUnicode; // utf-16be
else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
encoding = Encoding.UTF32;
else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
encoding = Encoding.UTF7;
using (MemoryStream stream = new MemoryStream())
{
stream.Write(buffer, 0, buffer.Length);
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream, encoding))
{
return reader.ReadToEnd();
}
}
}
}
Here's one I just created today.
// requires .NET 4
public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func,
TReturn elseValue = default(TReturn)) where TIn : class
{ return obj != null ? func(obj) : elseValue; }
// versions for CLR 2, which doesn't support optional params
public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func,
TReturn elseValue) where TIn : class
{ return obj != null ? func(obj) : elseValue; }
public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func)
where TIn : class
{ return obj != null ? func(obj) : default(TReturn); }
It lets you do this:
var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower());
which is more fluent and (IMO) easier to read than this:
var lname = (thingy != null ? thingy.Name : null) != null
? thingy.Name.ToLower() : null;
"Please mark your answers with an acceptance to put the code in the Codeplex project."
Why? All the Stuff on this site under CC-by-sa-2.5, so just put your Extension overflow Project under the same license and you can freely use it.
Anyway, here is a String.Reverse function, based on this question.
/// <summary>
/// Reverse a String
/// </summary>
/// <param name="input">The string to Reverse</param>
/// <returns>The reversed String</returns>
public static string Reverse(this string input)
{
char[] array = input.ToCharArray();
Array.Reverse(array);
return new string(array);
}
I got tired of tedious null-checking while pulling values from MySqlDataReader, so:
public static DateTime? GetNullableDateTime(this MySqlDataReader dr, string fieldName)
{
DateTime? nullDate = null;
return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullDate : dr.GetDateTime(fieldName);
}
public static string GetNullableString(this MySqlDataReader dr, string fieldName)
{
return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? String.Empty : dr.GetString(fieldName);
}
public static char? GetNullableChar(this MySqlDataReader dr, string fieldName)
{
char? nullChar = null;
return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullChar : dr.GetChar(fieldName);
}
Of course this could be used with any SqlDataReader.
Both hangy and Joe had some good comments on how to do this, and I have since had an opportunity to implement something similar in a different context, so here is another version:
public static int? GetNullableInt32(this IDataRecord dr, int ordinal)
{
int? nullInt = null;
return dr.IsDBNull(ordinal) ? nullInt : dr.GetInt32(ordinal);
}
public static int? GetNullableInt32(this IDataRecord dr, string fieldname)
{
int ordinal = dr.GetOrdinal(fieldname);
return dr.GetNullableInt32(ordinal);
}
public static bool? GetNullableBoolean(this IDataRecord dr, int ordinal)
{
bool? nullBool = null;
return dr.IsDBNull(ordinal) ? nullBool : dr.GetBoolean(ordinal);
}
public static bool? GetNullableBoolean(this IDataRecord dr, string fieldname)
{
int ordinal = dr.GetOrdinal(fieldname);
return dr.GetNullableBoolean(ordinal);
}
It irritated me that LINQ gives me an OrderBy that takes a class implementing IComparer as an argument, but does not support passing in a simple anonymous comparer function. I rectified that.
This class creates an IComparer from your comparer function...
/// <summary>
/// Creates an <see cref="IComparer{T}"/> instance for the given
/// delegate function.
/// </summary>
internal class ComparerFactory<T> : IComparer<T>
{
public static IComparer<T> Create(Func<T, T, int> comparison)
{
return new ComparerFactory<T>(comparison);
}
private readonly Func<T, T, int> _comparison;
private ComparerFactory(Func<T, T, int> comparison)
{
_comparison = comparison;
}
#region IComparer<T> Members
public int Compare(T x, T y)
{
return _comparison(x, y);
}
#endregion
}
...and these extension methods expose my new OrderBy overloads on enumerables. I doubt this works for LINQ to SQL, but it's great for LINQ to Objects.
public static class EnumerableExtensions
{
/// <summary>
/// Sorts the elements of a sequence in ascending order by using a specified comparison delegate.
/// </summary>
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, TKey, int> comparison)
{
var comparer = ComparerFactory<TKey>.Create(comparison);
return source.OrderBy(keySelector, comparer);
}
/// <summary>
/// Sorts the elements of a sequence in descending order by using a specified comparison delegate.
/// </summary>
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, TKey, int> comparison)
{
var comparer = ComparerFactory<TKey>.Create(comparison);
return source.OrderByDescending(keySelector, comparer);
}
}
You're welcome to put this on codeplex if you like.
This one is for MVC it adds the ability to generate a <label /> tag to the Html variable that is available in every ViewPage. Hopefully it will be of use to others trying to develop similar extensions.
Use:
<%= Html.Label("LabelId", "ForId", "Text")%>
Output:
<label id="LabelId" for="ForId">Text</label>
Code:
public static class HtmlHelperExtensions
{
public static string Label(this HtmlHelper Html, string #for, string text)
{
return Html.Label(null, #for, text);
}
public static string Label(this HtmlHelper Html, string #for, string text, object htmlAttributes)
{
return Html.Label(null, #for, text, htmlAttributes);
}
public static string Label(this HtmlHelper Html, string #for, string text, IDictionary<string, object> htmlAttributes)
{
return Html.Label(null, #for, text, htmlAttributes);
}
public static string Label(this HtmlHelper Html, string id, string #for, string text)
{
return Html.Label(id, #for, text, null);
}
public static string Label(this HtmlHelper Html, string id, string #for, string text, object htmlAttributes)
{
return Html.Label(id, #for, text, new RouteValueDictionary(htmlAttributes));
}
public static string Label(this HtmlHelper Html, string id, string #for, string text, IDictionary<string, object> htmlAttributes)
{
TagBuilder tag = new TagBuilder("label");
tag.MergeAttributes(htmlAttributes);
if (!string.IsNullOrEmpty(id))
tag.MergeAttribute("id", Html.AttributeEncode(id));
tag.MergeAttribute("for", Html.AttributeEncode(#for));
tag.SetInnerText(Html.Encode(text));
return tag.ToString(TagRenderMode.Normal);
}
}
Turn this:
DbCommand command = connection.CreateCommand();
command.CommandText = "SELECT #param";
DbParameter param = command.CreateParameter();
param.ParameterName = "#param";
param.Value = "Hello World";
command.Parameters.Add(param);
... into this:
DbCommand command = connection.CreateCommand("SELECT {0}", "Hello World");
... using this extension method:
using System;
using System.Data.Common;
using System.Globalization;
using System.Reflection;
namespace DbExtensions {
public static class Db {
static readonly Func<DbConnection, DbProviderFactory> getDbProviderFactory;
static readonly Func<DbCommandBuilder, int, string> getParameterName;
static readonly Func<DbCommandBuilder, int, string> getParameterPlaceholder;
static Db() {
getDbProviderFactory = (Func<DbConnection, DbProviderFactory>)Delegate.CreateDelegate(typeof(Func<DbConnection, DbProviderFactory>), typeof(DbConnection).GetProperty("DbProviderFactory", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true));
getParameterName = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterName", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null));
getParameterPlaceholder = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterPlaceholder", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null));
}
public static DbProviderFactory GetProviderFactory(this DbConnection connection) {
return getDbProviderFactory(connection);
}
public static DbCommand CreateCommand(this DbConnection connection, string commandText, params object[] parameters) {
if (connection == null) throw new ArgumentNullException("connection");
return CreateCommandImpl(GetProviderFactory(connection).CreateCommandBuilder(), connection.CreateCommand(), commandText, parameters);
}
private static DbCommand CreateCommandImpl(DbCommandBuilder commandBuilder, DbCommand command, string commandText, params object[] parameters) {
if (commandBuilder == null) throw new ArgumentNullException("commandBuilder");
if (command == null) throw new ArgumentNullException("command");
if (commandText == null) throw new ArgumentNullException("commandText");
if (parameters == null || parameters.Length == 0) {
command.CommandText = commandText;
return command;
}
object[] paramPlaceholders = new object[parameters.Length];
for (int i = 0; i < paramPlaceholders.Length; i++) {
DbParameter dbParam = command.CreateParameter();
dbParam.ParameterName = getParameterName(commandBuilder, i);
dbParam.Value = parameters[i] ?? DBNull.Value;
command.Parameters.Add(dbParam);
paramPlaceholders[i] = getParameterPlaceholder(commandBuilder, i);
}
command.CommandText = String.Format(CultureInfo.InvariantCulture, commandText, paramPlaceholders);
return command;
}
}
}
More ADO.NET extension methods: DbExtensions

What is the best or most interesting use of Extension Methods you've seen? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
I'm starting to really love extension methods... I was wondering if anyone her has stumbled upon one that really blew their mind, or just found clever.
An example I wrote today:
Edited due to other users' comments:
public static IEnumerable<int> To(this int fromNumber, int toNumber) {
while (fromNumber < toNumber) {
yield return fromNumber;
fromNumber++;
}
}
This allows a for loop to be written as a foreach loop:
foreach (int x in 0.To(16)) {
Console.WriteLine(Math.Pow(2, x).ToString());
}
I can't wait to see other examples! Enjoy!
This is one that's been getting some play from me lately:
public static IDisposable Tag(this HtmlHelper html, string tagName)
{
if (html == null)
throw new ArgumentNullException("html");
Action<string> a = tag => html.Write(String.Format(tag, tagName));
a("<{0}>");
return new Memento(() => a("</{0}>"));
}
Used like:
using (Html.Tag("ul"))
{
this.Model.ForEach(item => using(Html.Tag("li")) Html.Write(item));
using(Html.Tag("li")) Html.Write("new");
}
Memento is a handy class:
public sealed class Memento : IDisposable
{
private bool Disposed { get; set; }
private Action Action { get; set; }
public Memento(Action action)
{
if (action == null)
throw new ArgumentNullException("action");
Action = action;
}
void IDisposable.Dispose()
{
if (Disposed)
throw new ObjectDisposedException("Memento");
Disposed = true;
Action();
}
}
And to complete the dependencies:
public static void Write(this HtmlHelper html, string content)
{
if (html == null)
throw new ArgumentNullException("html");
html.ViewContext.HttpContext.Response.Write(content);
}
The full solution is too large to put here, but I wrote a series of extension methods that would allow you to easily convert a DataTable into a CSV.
public static String ToCSV(this DataTable dataTable)
{
return dataTable.ToCSV(null, COMMA, true);
}
public static String ToCSV(this DataTable dataTable, String qualifier)
{
return dataTable.ToCSV(qualifier, COMMA, true);
}
private static String ToCSV(this DataTable dataTable, String qualifier, String delimiter, Boolean includeColumnNames)
{
if (dataTable == null) return null;
if (qualifier == delimiter)
{
throw new InvalidOperationException(
"The qualifier and the delimiter are identical. This will cause the CSV to have collisions that might result in data being parsed incorrectly by another program.");
}
var sbCSV = new StringBuilder();
var delimiterToUse = delimiter ?? COMMA;
if (includeColumnNames)
sbCSV.AppendLine(dataTable.Columns.GetHeaderLine(qualifier, delimiterToUse));
foreach (DataRow row in dataTable.Rows)
{
sbCSV.AppendLine(row.ToCSVLine(qualifier, delimiterToUse));
}
return sbCSV.Length > 0 ? sbCSV.ToString() : null;
}
private static String ToCSVLine(this DataRow dataRow, String qualifier, String delimiter)
{
var colCount = dataRow.Table.Columns.Count;
var rowValues = new String[colCount];
for (var i = 0; i < colCount; i++)
{
rowValues[i] = dataRow[i].Qualify(qualifier);
}
return String.Join(delimiter, rowValues);
}
private static String GetHeaderLine(this DataColumnCollection columns, String qualifier, String delimiter)
{
var colCount = columns.Count;
var colNames = new String[colCount];
for (var i = 0; i < colCount; i++)
{
colNames[i] = columns[i].ColumnName.Qualify(qualifier);
}
return String.Join(delimiter, colNames);
}
private static String Qualify(this Object target, String qualifier)
{
return qualifier + target + qualifier;
}
At the end of the day, you could call it like this:
someDataTable.ToCSV(); //Plain old CSV
someDataTable.ToCSV("\""); //Double quote qualifier
someDataTable.ToCSV("\"", "\t"); //Tab delimited
I'm not a fan of the INotifyPropertyChanged interface requiring that property names are passed as strings. I want a strongly-typed way to check at compile time that I'm only raising and handling property changes for properties that exist. I use this code to do that:
public static class INotifyPropertyChangedExtensions
{
public static string ToPropertyName<T>(this Expression<Func<T>> #this)
{
var #return = string.Empty;
if (#this != null)
{
var memberExpression = #this.Body as MemberExpression;
if (memberExpression != null)
{
#return = memberExpression.Member.Name;
}
}
return #return;
}
}
In classes that implement INotifyPropertyChanged I include this helper method:
protected void NotifySetProperty<T>(ref T field, T value,
Expression<Func<T>> propertyExpression)
{
if (field == null ? value != null : !field.Equals(value))
{
field = value;
this.NotifyPropertyChanged(propertyExpression.ToPropertyName());
}
}
So that finally I can do this kind of thing:
private string _name;
public string Name
{
get { return _name; }
set { this.NotifySetProperty(ref _name, value, () => this.Name); }
}
It's strongly-typed and I only raise events for properties that actually change their value.
Well this isn't exactly clever but I've modified the ----OrDefault methods so you could specify a default item inline instead of checking for null later in your code:
public static T SingleOrDefault<T> ( this IEnumerable<T> source,
Func<T, bool> action, T theDefault )
{
T item = source.SingleOrDefault<T>(action);
if (item != null)
return item;
return theDefault;
}
Its incredible simple but really helps clean up those null checks. Best used when your UI is expecting a list of X items, like a tournament system, or game player slots and you want to display "empty seats".
Usage:
return jediList.SingleOrDefault(
j => j.LightsaberColor == "Orange",
new Jedi() { LightsaberColor = "Orange", Name = "DarthNobody");
Two that I like to use are the InsertWhere<T> and RemoveWhere<T> Extension Methods that I've written. Working with ObservableCollections in WPF and Silverlight I often need to modify ordered lists without recreating them. These methods allow me to insert and remove according to a supplied Func, so .OrderBy() doesn't need to be re-called.
/// <summary>
/// Removes all items from the provided <paramref name="list"/> that match the<paramref name="predicate"/> expression.
/// </summary>
/// <typeparam name="T">The class type of the list items.</typeparam>
/// <param name="list">The list to remove items from.</param>
/// <param name="predicate">The predicate expression to test against.</param>
public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate)
{
T[] copy = new T[] { };
Array.Resize(ref copy, list.Count);
list.CopyTo(copy, 0);
for (int i = copy.Length - 1; i >= 0; i--)
{
if (predicate(copy[i]))
{
list.RemoveAt(i);
}
}
}
/// <summary>
/// Inserts an Item into a list at the first place that the <paramref name="predicate"/> expression fails. If it is true in all cases, then the item is appended to the end of the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="obj"></param>
/// <param name="predicate">The sepcified function that determines when the <paramref name="obj"/> should be added. </param>
public static void InsertWhere<T>(this IList<T> list, T obj, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++)
{
// When the function first fails it inserts the obj paramiter.
// For example, in a list myList of ordered Int32's {1,2,3,4,5,10,12}
// Calling myList.InsertWhere( 8, x => 8 > x) inserts 8 once the list item becomes greater then or equal to it.
if(!predicate(list[i]))
{
list.Insert(i, obj);
return;
}
}
list.Add(obj);
}
Edit:
Talljoe made some significant improvements to the RemoveWhere/RemoveAll, that I had hastily constructed. With ~3mill items removing every third one the new version takes only ~50 milliseconds (less then 10 if it can call List.RemoveAll !) as opposed to the RemoveWhere 's multiple seconds (I got tired of waiting for it.)
Here is his greatly improved version, thanks again!
public static void RemoveAll<T>(this IList<T> instance, Predicate<T> predicate)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (predicate == null)
throw new ArgumentNullException("predicate");
if (instance is T[])
throw new NotSupportedException();
var list = instance as List<T>;
if (list != null)
{
list.RemoveAll(predicate);
return;
}
int writeIndex = 0;
for (int readIndex = 0; readIndex < instance.Count; readIndex++)
{
var item = instance[readIndex];
if (predicate(item)) continue;
if (readIndex != writeIndex)
{
instance[writeIndex] = item;
}
++writeIndex;
}
if (writeIndex != instance.Count)
{
for (int deleteIndex = instance.Count - 1; deleteIndex >= writeIndex; --deleteIndex)
{
instance.RemoveAt(deleteIndex);
}
}
}
I have various .Debugify extension methods that are useful for dumping objects to a log file. For example, here's my Dictionary debugify (I have these for List, Datatable, param array, etc.):
public static string Debugify<TKey, TValue>(this Dictionary<TKey, TValue> dictionary) {
string Result = "";
if (dictionary.Count > 0) {
StringBuilder ResultBuilder = new StringBuilder();
int Counter = 0;
foreach (KeyValuePair<TKey, TValue> Entry in dictionary) {
Counter++;
ResultBuilder.AppendFormat("{0}: {1}, ", Entry.Key, Entry.Value);
if (Counter % 10 == 0) ResultBuilder.AppendLine();
}
Result = ResultBuilder.ToString();
}
return Result;
}
And here's one for a DbParameterCollection (useful for dumping database calls to the log file):
public static string Debugify(this DbParameterCollection parameters) {
List<string> ParameterValuesList = new List<string>();
foreach (DbParameter Parameter in parameters) {
string ParameterName, ParameterValue;
ParameterName = Parameter.ParameterName;
if (Parameter.Direction == ParameterDirection.ReturnValue)
continue;
if (Parameter.Value == null || Parameter.Value.Equals(DBNull.Value))
ParameterValue = "NULL";
else
{
switch (Parameter.DbType)
{
case DbType.String:
case DbType.Date:
case DbType.DateTime:
case DbType.Guid:
case DbType.Xml:
ParameterValue
= "'" + Parameter
.Value
.ToString()
.Replace(Environment.NewLine, "")
.Left(80, "...") + "'"; // Left... is another nice one
break;
default:
ParameterValue = Parameter.Value.ToString();
break;
}
if (Parameter.Direction != ParameterDirection.Input)
ParameterValue += " " + Parameter.Direction.ToString();
}
ParameterValuesList.Add(string.Format("{0}={1}", ParameterName, ParameterValue));
}
return string.Join(", ", ParameterValuesList.ToArray());
}
Example result:
Log.DebugFormat("EXEC {0} {1}", procName, params.Debugify);
// EXEC spProcedure #intID=5, #nvName='Michael Haren', #intRefID=11 OUTPUT
Note that if you call this after your DB calls, you'll get the output parameters filled in, too. I call this on a line that includes the SP name so I can copy/paste the call into SSMS for debugging.
These make my log files pretty and easy to generate without interrupting my code.
Here's one I hacked together, so feel free to pick holes in it. It takes an (ordered) list of integers and returns a list of strings of contiguous ranges. eg:
1,2,3,7,10,11,12 --> "1-3","7","10-12"
The function (within a static class):
public static IEnumerable<string> IntRanges(this IEnumerable<int> numbers)
{
int rangeStart = 0;
int previous = 0;
if (!numbers.Any())
yield break;
rangeStart = previous = numbers.FirstOrDefault();
foreach (int n in numbers.Skip(1))
{
if (n - previous > 1) // sequence break - yield a sequence
{
if (previous > rangeStart)
{
yield return string.Format("{0}-{1}", rangeStart, previous);
}
else
{
yield return rangeStart.ToString();
}
rangeStart = n;
}
previous = n;
}
if (previous > rangeStart)
{
yield return string.Format("{0}-{1}", rangeStart, previous);
}
else
{
yield return rangeStart.ToString();
}
}
Usage example:
this.WeekDescription = string.Join(",", from.WeekPattern.WeekPatternToInts().IntRanges().ToArray());
This code is used to convert data from a DailyWTF-worthy timetabling application. WeekPattern is a bitmask stored in a string "0011011100...". WeekPatternToInts() converts that to an IEnumerable<int>, in this case [3,4,6,7,8], which becomes "3-4,6-8". It provides the user with a compact description of the academic week ranges that a lecture occurs on.
A pair of extension methods to convert base-36 strings(!) to integers:
public static int ToBase10(this string base36)
{
if (string.IsNullOrEmpty(base36))
return 0;
int value = 0;
foreach (var c in base36.Trim())
{
value = value * 36 + c.ToBase10();
}
return value;
}
public static int ToBase10(this char c)
{
if (c >= '0' && c <= '9')
return c - '0';
c = char.ToUpper(c);
if (c >= 'A' && c <= 'Z')
return c - 'A' + 10;
return 0;
}
(Some genius decided that the best way to store numbers in the database was to encode them to strings. Decimals take too much space. Hex is better, but doesnt use the characters G-Z. So obviously you extend base-16 to base-36!)
I wrote a series of extension methods to make it easier to manipulate ADO.NET objects and methods :
Create a DbCommand from a DbConnection in one instruction :
public static DbCommand CreateCommand(this DbConnection connection, string commandText)
{
DbCommand command = connection.CreateCommand();
command.CommandText = commandText;
return command;
}
Add a parameter to a DbCommand :
public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType)
{
DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
return p;
}
public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, object value)
{
DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
p.Value = value;
return p;
}
public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size)
{
return AddParameter(command, name, dbType, size, ParameterDirection.Input);
}
public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size, ParameterDirection direction)
{
DbParameter parameter = command.CreateParameter();
parameter.ParameterName = name;
parameter.DbType = dbType;
parameter.Direction = direction;
parameter.Size = size;
command.Parameters.Add(parameter);
return parameter;
}
Access DbDataReader fields by name rather than index :
public static DateTime GetDateTime(this DbDataReader reader, string name)
{
int i = reader.GetOrdinal(name);
return reader.GetDateTime(i);
}
public static decimal GetDecimal(this DbDataReader reader, string name)
{
int i = reader.GetOrdinal(name);
return reader.GetDecimal(i);
}
public static double GetDouble(this DbDataReader reader, string name)
{
int i = reader.GetOrdinal(name);
return reader.GetDouble(i);
}
public static string GetString(this DbDataReader reader, string name)
{
int i = reader.GetOrdinal(name);
return reader.GetString(i);
}
...
Another (unrelated) extension method allows me to perform the DragMove operation (like in WPF) on WinForms forms and controls, see here.
Most examples for extension methods that I see here go against best practises.
Extension methods are powerful, but should be used sparingly. In my experience, a static helper/utility class with old-school syntax would generally be preferrable for most of these.
There is something to say for extension methods for Enums, as it's not possible for them to have methods. If you define them in the same namespace as your Enum and in the same assembly, they work transparently.
While very simple, I find this one to be particularly useful since I get a page out of a full result set ten billion times a project:
public static class QueryableExtensions
{
public static IQueryable<T> Page(this IQueryable<T> query, int pageNumber, int pageSize)
{
int skipCount = (pageNumber-1) * pageSize;
query = query.Skip(skipCount);
query = query.Take(pageSize);
return query;
}
}
Often times, I've needed to display a user-friendly value based on an Enum value, but didn't want to go the custom Attribute route, as it didn't seem too elegant.
With this handy extension method:
public static string EnumValue(this MyEnum e) {
switch (e) {
case MyEnum.First:
return "First Friendly Value";
case MyEnum.Second:
return "Second Friendly Value";
case MyEnum.Third:
return "Third Friendly Value";
}
return "Horrible Failure!!";
}
I can do this:
Console.WriteLine(MyEnum.First.EnumValue());
Yay!
This is an extension method to centralize null checks before raising events.
public static class EventExtension
{
public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs
{
EventHandler<T> theHandler = handler;
if (theHandler != null)
{
theHandler(obj, args);
}
}
}
This one is incredibly simple, but it's a check I do a lot so I ended up making an extension method for it. My favorite extension methods tend to be the really simple, straightforward ones like this, or like Taylor L's extension method for raising events.
public static bool IsNullOrEmpty(this ICollection e)
{
return e == null || e.Count == 0;
}
To allow more functional combinator code:
public static Func<T, R> TryCoalesce<T, R>(this Func<T, R> f, R coalesce)
{
return x =>
{
try
{
return f(x);
}
catch
{
return coalesce;
}
};
}
public static TResult TryCoalesce<T, TResult>(this Func<T, TResult> f, T p, TResult coalesce)
{
return f.TryCoalesce(coalesce)(p);
}
Then I could write something like this:
public static int ParseInt(this string str, int coalesce)
{
return TryCoalesce(int.Parse, str, coalesce);
}
Another set I use quite often is for coalescing IDictionary methods:
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> valueThunk)
{
TValue v = d.Get(key);
if (v == null)
{
v = valueThunk();
d.Add(key, v);
}
return v;
}
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, TValue coalesce)
{
return Get(d, key, () => coalesce);
}
And for working with collections in general:
public static IEnumerable<T> AsCollection<T>(this T item)
{
yield return item;
}
Then for tree-like structures:
public static LinkedList<T> Up<T>(this T node, Func<T, T> parent)
{
var list = new LinkedList<T>();
node.Up(parent, n => list.AddFirst(n));
return list;
}
So I can then easily traverse and operate upon a up a class like:
class Category
{
public string Name { get; set; }
public Category Parent { get; set; }
}
Next, to facilitate function composition and a more F# like way of programming in C#:
public static Func<T, T> Func<T>(this Func<T, T> f)
{
return f;
}
public static Func<T1, R> Compose<T1, T2, R>(this Func<T1, T2> f, Func<T2, R> g)
{
return x => g(f(x));
}
I am converting a lot of Java to C#. Many of the methods vary only in capitalization or other small syntax differences. So Java code such as
myString.toLowerCase();
will not compile but by adding an extension method
public static void toLowerCase(this string s)
{
s.ToLower();
}
I can catch all the methods (and I assume a good compiler will inline this anyway?).
It's certainly made the job much easier and more reliable.
(I thank #Yuriy - see answer in: differences between StringBuilder in Java and C#) for the suggestion.
I like this one. It is a variation on the String.Split method that allows the use of an escape character to suppress splitting when the split character is intended to be in the actual string.
Extension method on int to decode a bitmask specifying days (with first day of week being Monday in this case) to an enumeration of DayOfWeek enums:
public static IEnumerable<DayOfWeek> Days(this int dayMask)
{
if ((dayMask & 1) > 0) yield return DayOfWeek.Monday;
if ((dayMask & 2) > 0) yield return DayOfWeek.Tuesday;
if ((dayMask & 4) > 0) yield return DayOfWeek.Wednesday;
if ((dayMask & 8) > 0) yield return DayOfWeek.Thursday;
if ((dayMask & 16) > 0) yield return DayOfWeek.Friday;
if ((dayMask & 32) > 0) yield return DayOfWeek.Saturday;
if ((dayMask & 64) > 0) yield return DayOfWeek.Sunday;
}
This one creates array with single element added at the very beginning:
public static T[] Prepend<T>(this T[] array, T item)
{
T[] result = new T[array.Length + 1];
result[0] = item;
Array.Copy(array, 0, result, 1, array.Length);
return result;
}
string[] some = new string[] { "foo", "bar" };
...
some = some.Prepend("baz");
And this one helps me when I need to convert some expression to it's square:
public static double Sq(this double arg)
{
return arg * arg;
}
(x - x0).Sq() + (y - y0).Sq() + (z - z0).Sq()
Here's another one I wrote:
public static class StringExtensions
{
/// <summary>
/// Returns a Subset string starting at the specified start index and ending and the specified end
/// index.
/// </summary>
/// <param name="s">The string to retrieve the subset from.</param>
/// <param name="startIndex">The specified start index for the subset.</param>
/// <param name="endIndex">The specified end index for the subset.</param>
/// <returns>A Subset string starting at the specified start index and ending and the specified end
/// index.</returns>
public static string Subsetstring(this string s, int startIndex, int endIndex)
{
if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "Must be positive.");
if (endIndex < 0) throw new ArgumentOutOfRangeException("endIndex", "Must be positive.");
if (startIndex > endIndex) throw new ArgumentOutOfRangeException("endIndex", "Must be >= startIndex.");
return s.Substring(startIndex, (endIndex - startIndex));
}
/// <summary>
/// Finds the specified Start Text and the End Text in this string instance, and returns a string
/// containing all the text starting from startText, to the begining of endText. (endText is not
/// included.)
/// </summary>
/// <param name="s">The string to retrieve the subset from.</param>
/// <param name="startText">The Start Text to begin the Subset from.</param>
/// <param name="endText">The End Text to where the Subset goes to.</param>
/// <param name="ignoreCase">Whether or not to ignore case when comparing startText/endText to the string.</param>
/// <returns>A string containing all the text starting from startText, to the begining of endText.</returns>
public static string Subsetstring(this string s, string startText, string endText, bool ignoreCase)
{
if (string.IsNullOrEmpty(startText)) throw new ArgumentNullException("startText", "Must be filled.");
if (string.IsNullOrEmpty(endText)) throw new ArgumentNullException("endText", "Must be filled.");
string temp = s;
if (ignoreCase)
{
temp = s.ToUpperInvariant();
startText = startText.ToUpperInvariant();
endText = endText.ToUpperInvariant();
}
int start = temp.IndexOf(startText);
int end = temp.IndexOf(endText, start);
return Subsetstring(s, start, end);
}
}
The motivation behind this one was simple. It always bugged me how the built in Substring method took startindex and length as it's parameters. It's ALWAYS much more helpful to do startindex and endindex. So, I rolled my own:
Usage:
string s = "This is a tester for my cool extension method!!";
s = s.Subsetstring("tester", "cool",true);
The reason I had to use Subsetstring was because Substring's overload already takes two ints. If anyone has a better name, please, let me know!!
cool, also loving Extensions!
here's a few.
This one will get the last Date of a Month:
<System.Runtime.CompilerServices.Extension()> _
Public Function GetLastMonthDay(ByVal Source As DateTime) As DateTime
Dim CurrentMonth As Integer = Source.Month
Dim MonthCounter As Integer = Source.Month
Dim LastDay As DateTime
Dim DateCounter As DateTime = Source
LastDay = Source
Do While MonthCounter = CurrentMonth
DateCounter = DateCounter.AddDays(1)
MonthCounter = DateCounter.Month
If MonthCounter = CurrentMonth Then
LastDay = DateCounter
End If
Loop
Return LastDay
End Function
these two make reflection a bit easier:
<System.Runtime.CompilerServices.Extension()> _
Public Function GetPropertyValue(Of ValueType)(ByVal Source As Object, ByVal PropertyName As String) As ValueType
Dim pInfo As System.Reflection.PropertyInfo
pInfo = Source.GetType.GetProperty(PropertyName)
If pInfo Is Nothing Then
Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
Else
Return pInfo.GetValue(Source, Nothing)
End If
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function GetPropertyType(ByVal Source As Object, ByVal PropertyName As String) As Type
Dim pInfo As System.Reflection.PropertyInfo
pInfo = Source.GetType.GetProperty(PropertyName)
If pInfo Is Nothing Then
Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
Else
Return pInfo.PropertyType
End If
End Function
The extension methods I use the most would have to be the ones in the System.Linq.Enumerable class.
And a good and useful extension to that list you can find in MoreLinq.
There are a couple that I've mentioned here that I use:
Easier checking on flags enums
if( enumVar.IsSet( MyEnum.PossibleFlag ) ) //..then
Inline checking of nulls
myObject.IfNotNull( x => x.Property );
few extensions I use mostly. first set is object extensions, really only for converting.
public static class ObjectExtension
{
public static T As<T>(this object value)
{
return (value != null && value is T) ? (T)value : default(T);
}
public static int AsInt(this string value)
{
if (value.HasValue())
{
int result;
var success = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
if (success)
{
return result;
}
}
return 0;
}
public static Guid AsGuid(this string value)
{
return value.HasValue() ? new Guid(value) : Guid.Empty;
}
}
string extensions
public static class StringExtension
{
public static bool HasValue(this string value)
{
return string.IsNullOrEmpty(value) == false;
}
public static string Slug(this string value)
{
if (value.HasValue())
{
var builder = new StringBuilder();
var slug = value.Trim().ToLower();
foreach (var c in slug)
{
switch (c)
{
case ' ':
builder.Append("-");
break;
case '&':
builder.Append("and");
break;
default:
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') && c != '-')
{
builder.Append(c);
}
break;
}
}
return builder.ToString();
}
return string.Empty;
}
public static string Truncate(this string value, int limit)
{
return (value.Length > limit) ? string.Concat(value.Substring(0, Math.Min(value.Length, limit)), "...") : value;
}
}
and last is some enum extensions
public static class EnumExtensions
{
public static bool Has<T>(this Enum source, params T[] values)
{
var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
foreach (var i in values)
{
var mask = Convert.ToInt32(i, CultureInfo.InvariantCulture);
if ((value & mask) == 0)
{
return false;
}
}
return true;
}
public static bool Has<T>(this Enum source, T values)
{
var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
var mask = Convert.ToInt32(values, CultureInfo.InvariantCulture);
return (value & mask) != 0;
}
public static T Add<T>(this Enum source, T v)
{
var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);
return Enum.ToObject(typeof(T), value | mask).As<T>();
}
public static T Remove<T>(this Enum source, T v)
{
var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);
return Enum.ToObject(typeof(T), value & ~mask).As<T>();
}
public static T AsEnum<T>(this string value)
{
try
{
return Enum.Parse(typeof(T), value, true).As<T>();
}
catch
{
return default(T);
}
}
}
With regular use of StringBuilder, you may see the need to combine AppendFormat() and AppendLine().
public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
Also, since I'm converting an application from VB6 to C#, the following are very useful to me:
public static string Left(this string s, int length)
{
if (s.Length >= length)
return s.Substring(0, length);
throw new ArgumentException("Length must be less than the length of the string.");
}
public static string Right(this string s, int length)
{
if (s.Length >= length)
return s.Substring(s.Length - length, length);
throw new ArgumentException("Length must be less than the length of the string.");
}
My favourite from my own personal collection of string utils is one that will parse a strongly typed value from a string for any type that has a TryParse method:
public static class StringUtils
{
/// <summary>
/// This method will parse a value from a string.
/// If the string is null or not the right format to parse a valid value,
/// it will return the default value provided.
/// </summary>
public static T To<t>(this string value, T defaultValue)
where T: struct
{
var type = typeof(T);
if (value != null)
{
var parse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
var parameters = new object[] { value, default(T) };
if((bool)parse.Invoke(null, parameters))
return (T)parameters[1];
}
return defaultValue;
}
/// <summary>
/// This method will parse a value from a string.
/// If the string is null or not the right format to parse a valid value,
/// it will return the default value for the type.
/// </summary>
public static T To<t>(this string value)
where T : struct
{
return value.To<t>(default(T));
}
}
It's great for getting strongly typed information from query strings:
var value = Request.QueryString["value"].To<int>();
I hate having to do this everywhere:
DataSet ds = dataLayer.GetSomeData(1, 2, 3);
if(ds != null){
if(ds.Tables.Count > 0){
DataTable dt = ds.Tables[0];
foreach(DataRow dr in dt.Rows){
//Do some processing
}
}
}
Instead I usually use the following Extension Method:
public static IEnumerable<DataRow> DataRows(this DataSet current){
if(current != null){
if(current.Tables.Count > 0){
DataTable dt = current.Tables[0];
foreach(DataRow dr in dt.Rows){
yield return dr;
}
}
}
}
So the first example then becomes:
foreach(DataRow row in ds.DataRows()){
//Do some processing
}
Yay, Extension Methods!
String.format should not have been static. So I use an extension method called frmt:
<Extension()> Public Function frmt(ByVal format As String,
ByVal ParamArray args() As Object) As String
If format Is Nothing Then Throw New ArgumentNullException("format")
Return String.Format(format, args)
End Function
When I want to read or write a number to a byte stream without constructing a binary writer (technically you aren't supposed to modify the raw stream after you've wrapped it with a writer):
<Extension()> Public Function Bytes(ByVal n As ULong,
ByVal byteOrder As ByteOrder,
Optional ByVal size As Integer = 8) As Byte()
Dim data As New List(Of Byte)
Do Until data.Count >= size
data.Add(CByte(n And CULng(&HFF)))
n >>= 8
Loop
Select Case byteOrder
Case ByteOrder.BigEndian
Return data.ToArray.reversed
Case ByteOrder.LittleEndian
Return data.ToArray
Case Else
Throw New ArgumentException("Unrecognized byte order.")
End Select
End Function
<Extension()> Public Function ToULong(ByVal data As IEnumerable(Of Byte),
ByVal byteOrder As ByteOrder) As ULong
If data Is Nothing Then Throw New ArgumentNullException("data")
Dim val As ULong
Select Case byteOrder
Case ByteOrder.LittleEndian
data = data.Reverse
Case ByteOrder.BigEndian
'no change required
Case Else
Throw New ArgumentException("Unrecognized byte order.")
End Select
For Each b In data
val <<= 8
val = val Or b
Next b
Return val
End Function
This one shifts a sequence so that you get the given item first. I used it for example to take the day of weeks and shift it so that the first day in the sequence is the first day of the week for the current culture.
/// <summary>
/// Shifts a sequence so that the given <paramref name="item"/> becomes the first.
/// Uses the specified equality <paramref name="comparer"/> to find the item.
/// </summary>
/// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
/// <param name="source">Sequence of elements.</param>
/// <param name="item">Item which will become the first.</param>
/// <param name="comparer">Used to find the first item.</param>
/// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource item, IEqualityComparer<TSource> comparer)
{
var queue = new Queue<TSource>();
bool found = false;
foreach (TSource e in source)
{
if (!found && comparer.Equals(item, e))
found = true;
if (found)
yield return e;
else
queue.Enqueue(e);
}
while (queue.Count > 0)
yield return queue.Dequeue();
}
/// <summary>
/// Shifts a sequence so that the given item becomes the first.
/// Uses the default equality comparer to find the item.
/// </summary>
/// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
/// <param name="source">Sequence of elements.</param>
/// <param name="element">Element which will become the first.</param>
/// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource element)
{
return Shift(source, element, EqualityComparer<TSource>.Default);
}

Comparing object properties in c# [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Closed 4 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
This is what I've come up with as a method on a class inherited by many of my other classes. The idea is that it allows the simple comparison between properties of Objects of the same Type.
Now, this does work - but in the interest of improving the quality of my code I thought I'd throw it out for scrutiny. How can it be better/more efficient/etc.?
/// <summary>
/// Compare property values (as strings)
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public bool PropertiesEqual(object comparisonObject)
{
Type sourceType = this.GetType();
Type destinationType = comparisonObject.GetType();
if (sourceType == destinationType)
{
PropertyInfo[] sourceProperties = sourceType.GetProperties();
foreach (PropertyInfo pi in sourceProperties)
{
if ((sourceType.GetProperty(pi.Name).GetValue(this, null) == null && destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null) == null))
{
// if both are null, don't try to compare (throws exception)
}
else if (!(sourceType.GetProperty(pi.Name).GetValue(this, null).ToString() == destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null).ToString()))
{
// only need one property to be different to fail Equals.
return false;
}
}
}
else
{
throw new ArgumentException("Comparison object must be of the same type.","comparisonObject");
}
return true;
}
I was looking for a snippet of code that would do something similar to help with writing unit test. Here is what I ended up using.
public static bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
Type type = typeof(T);
List<string> ignoreList = new List<string>(ignore);
foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
if (!ignoreList.Contains(pi.Name))
{
object selfValue = type.GetProperty(pi.Name).GetValue(self, null);
object toValue = type.GetProperty(pi.Name).GetValue(to, null);
if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)))
{
return false;
}
}
}
return true;
}
return self == to;
}
EDIT:
Same code as above but uses LINQ and Extension methods :
public static bool PublicInstancePropertiesEqual<T>(this T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
var type = typeof(T);
var ignoreList = new List<string>(ignore);
var unequalProperties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where !ignoreList.Contains(pi.Name) && pi.GetUnderlyingType().IsSimpleType() && pi.GetIndexParameters().Length == 0
let selfValue = type.GetProperty(pi.Name).GetValue(self, null)
let toValue = type.GetProperty(pi.Name).GetValue(to, null)
where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))
select selfValue;
return !unequalProperties.Any();
}
return self == to;
}
public static class TypeExtensions
{
/// <summary>
/// Determine whether a type is simple (String, Decimal, DateTime, etc)
/// or complex (i.e. custom class with public properties and methods).
/// </summary>
/// <see cref="http://stackoverflow.com/questions/2442534/how-to-test-if-type-is-primitive"/>
public static bool IsSimpleType(
this Type type)
{
return
type.IsValueType ||
type.IsPrimitive ||
new[]
{
typeof(String),
typeof(Decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
(Convert.GetTypeCode(type) != TypeCode.Object);
}
public static Type GetUnderlyingType(this MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
default:
throw new ArgumentException
(
"Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo"
);
}
}
}
UPDATE: The latest version of Compare-Net-Objects is located on GitHub , has NuGet package and Tutorial. It can be called like
//This is the comparison class
CompareLogic compareLogic = new CompareLogic();
ComparisonResult result = compareLogic.Compare(person1, person2);
//These will be different, write out the differences
if (!result.AreEqual)
Console.WriteLine(result.DifferencesString);
Or if you need to change some configuration, use
CompareLogic basicComparison = new CompareLogic()
{ Config = new ComparisonConfig()
{ MaxDifferences = propertyCount
//add other configurations
}
};
Full list of configurable parameters is in ComparisonConfig.cs
Original answer:
The limitations I see in your code:
The biggest one is that it doesn't do a deep object comparison.
It doesn't do an element by element comparison in case properties are lists or contain lists as elements (this can go n-levels).
It doesn't take into account that some type of properties should not be compared (e.g. a Func property used for filtering purposes, like the one in the PagedCollectionView class).
It doesn't keep track of what properties actually were different (so you can show in your assertions).
I was looking today for some solution for unit-testing purposes to do property by property deep comparison and I ended up using: http://comparenetobjects.codeplex.com.
It is a free library with just one class which you can simply use like this:
var compareObjects = new CompareObjects()
{
CompareChildren = true, //this turns deep compare one, otherwise it's shallow
CompareFields = false,
CompareReadOnly = true,
ComparePrivateFields = false,
ComparePrivateProperties = false,
CompareProperties = true,
MaxDifferences = 1,
ElementsToIgnore = new List<string>() { "Filter" }
};
Assert.IsTrue(
compareObjects.Compare(objectA, objectB),
compareObjects.DifferencesString
);
Also, it can be easily re-compiled for Silverlight. Just copy the one class into a Silverlight project and remove one or two lines of code for comparisons that are not available in Silverlight, like private members comparison.
I think it would be best to follow the pattern for Override Object#Equals()
For a better description: Read Bill Wagner's Effective C# - Item 9 I think
public override Equals(object obOther)
{
if (null == obOther)
return false;
if (object.ReferenceEquals(this, obOther)
return true;
if (this.GetType() != obOther.GetType())
return false;
# private method to compare members.
return CompareMembers(this, obOther as ThisClass);
}
Also in methods that check for equality, you should return either true or false. either they are equal or they are not.. instead of throwing an exception, return false.
I'd consider overriding Object#Equals.
Even though you must have considered this, using Reflection to compare properties is supposedly slow (I dont have numbers to back this up). This is the default behavior for valueType#Equals in C# and it is recommended that you override Equals for value types and do a member wise compare for performance. (Earlier I speed-read this as you have a collection of custom Property objects... my bad.)
Update-Dec 2011:
Of course, if the type already has a production Equals() then you need another approach.
If you're using this to compare immutable data structures exclusively for test purposes, you shouldn't add an Equals to production classes (Someone might hose the tests by chainging the Equals implementation or you may prevent creation of a production-required Equals implementation).
If performance doesn't matter, you could serialize them and compare the results:
var serializer = new XmlSerializer(typeof(TheObjectType));
StringWriter serialized1 = new StringWriter(), serialized2 = new StringWriter();
serializer.Serialize(serialized1, obj1);
serializer.Serialize(serialized2, obj2);
bool areEqual = serialized1.ToString() == serialized2.ToString();
I think the answer of Big T was quite good but the deep comparison was missing, so I tweaked it a little bit:
using System.Collections.Generic;
using System.Reflection;
/// <summary>Comparison class.</summary>
public static class Compare
{
/// <summary>Compare the public instance properties. Uses deep comparison.</summary>
/// <param name="self">The reference object.</param>
/// <param name="to">The object to compare.</param>
/// <param name="ignore">Ignore property with name.</param>
/// <typeparam name="T">Type of objects.</typeparam>
/// <returns><see cref="bool">True</see> if both objects are equal, else <see cref="bool">false</see>.</returns>
public static bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
var type = self.GetType();
var ignoreList = new List<string>(ignore);
foreach (var pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (ignoreList.Contains(pi.Name))
{
continue;
}
var selfValue = type.GetProperty(pi.Name).GetValue(self, null);
var toValue = type.GetProperty(pi.Name).GetValue(to, null);
if (pi.PropertyType.IsClass && !pi.PropertyType.Module.ScopeName.Equals("CommonLanguageRuntimeLibrary"))
{
// Check of "CommonLanguageRuntimeLibrary" is needed because string is also a class
if (PublicInstancePropertiesEqual(selfValue, toValue, ignore))
{
continue;
}
return false;
}
if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)))
{
return false;
}
}
return true;
}
return self == to;
}
}
I would add the following line to the PublicInstancePropertiesEqual method to avoid copy & paste errors:
Assert.AreNotSame(self, to);
Do you override .ToString() on all of your objects that are in the properties? Otherwise, that second comparison could come back with null.
Also, in that second comparison, I'm on the fence about the construct of !( A == B) compared to (A != B), in terms of readability six months/two years from now. The line itself is pretty wide, which is ok if you've got a wide monitor, but might not print out very well. (nitpick)
Are all of your objects always using properties such that this code will work? Could there be some internal, non-propertied data that could be different from one object to another, but all exposed data is the same? I'm thinking of some data which could change over time, like two random number generators that happen to hit the same number at one point, but are going to produce two different sequences of information, or just any data that doesn't get exposed through the property interface.
If you are only comparing objects of the same type or further down the inheritance chain, why not specify the parameter as your base type, rather than object ?
Also do null checks on the parameter as well.
Furthermore I'd make use of 'var' just to make the code more readable (if its c#3 code)
Also, if the object has reference types as properties then you are just calling ToString() on them which doesn't really compare values. If ToString isn't overwridden then its just going to return the type name as a string which could return false-positives.
The first thing I would suggest would be to split up the actual comparison so that it's a bit more readable (I've also taken out the ToString() - is that needed?):
else {
object originalProperty = sourceType.GetProperty(pi.Name).GetValue(this, null);
object comparisonProperty = destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null);
if (originalProperty != comparisonProperty)
return false;
The next suggestion would be to minimise the use of reflection as much as possible - it's really slow. I mean, really slow. If you are going to do this, I would suggest caching the property references. I'm not intimately familiar with the Reflection API, so if this is a bit off, just adjust to make it compile:
// elsewhere
Dictionary<object, Property[]> lookupDictionary = new Dictionary<object, Property[]>;
Property[] objectProperties = null;
if (lookupDictionary.ContainsKey(sourceType)) {
objectProperties = lookupProperties[sourceType];
} else {
// build array of Property references
PropertyInfo[] sourcePropertyInfos = sourceType.GetProperties();
Property[] sourceProperties = new Property[sourcePropertyInfos.length];
for (int i=0; i < sourcePropertyInfos.length; i++) {
sourceProperties[i] = sourceType.GetProperty(pi.Name);
}
// add to cache
objectProperties = sourceProperties;
lookupDictionary[object] = sourceProperties;
}
// loop through and compare against the instances
However, I have to say that I agree with the other posters. This smells lazy and inefficient. You should be implementing IComparable instead :-).
here is revised one to treat null = null as equal
private bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
Type type = typeof(T);
List<string> ignoreList = new List<string>(ignore);
foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (!ignoreList.Contains(pi.Name))
{
object selfValue = type.GetProperty(pi.Name).GetValue(self, null);
object toValue = type.GetProperty(pi.Name).GetValue(to, null);
if (selfValue != null)
{
if (!selfValue.Equals(toValue))
return false;
}
else if (toValue != null)
return false;
}
}
return true;
}
return self == to;
}
I ended up doing this:
public static string ToStringNullSafe(this object obj)
{
return obj != null ? obj.ToString() : String.Empty;
}
public static bool Compare<T>(T a, T b)
{
int count = a.GetType().GetProperties().Count();
string aa, bb;
for (int i = 0; i < count; i++)
{
aa = a.GetType().GetProperties()[i].GetValue(a, null).ToStringNullSafe();
bb = b.GetType().GetProperties()[i].GetValue(b, null).ToStringNullSafe();
if (aa != bb)
{
return false;
}
}
return true;
}
Usage:
if (Compare<ObjectType>(a, b))
Update
If you want to ignore some properties by name:
public static string ToStringNullSafe(this object obj)
{
return obj != null ? obj.ToString() : String.Empty;
}
public static bool Compare<T>(T a, T b, params string[] ignore)
{
int count = a.GetType().GetProperties().Count();
string aa, bb;
for (int i = 0; i < count; i++)
{
aa = a.GetType().GetProperties()[i].GetValue(a, null).ToStringNullSafe();
bb = b.GetType().GetProperties()[i].GetValue(b, null).ToStringNullSafe();
if (aa != bb && ignore.Where(x => x == a.GetType().GetProperties()[i].Name).Count() == 0)
{
return false;
}
}
return true;
}
Usage:
if (MyFunction.Compare<ObjType>(a, b, "Id","AnotherProp"))
You can optimize your code by calling GetProperties only once per type:
public static string ToStringNullSafe(this object obj)
{
return obj != null ? obj.ToString() : String.Empty;
}
public static bool Compare<T>(T a, T b, params string[] ignore)
{
var aProps = a.GetType().GetProperties();
var bProps = b.GetType().GetProperties();
int count = aProps.Count();
string aa, bb;
for (int i = 0; i < count; i++)
{
aa = aProps[i].GetValue(a, null).ToStringNullSafe();
bb = bProps[i].GetValue(b, null).ToStringNullSafe();
if (aa != bb && ignore.Where(x => x == aProps[i].Name).Count() == 0)
{
return false;
}
}
return true;
}
For completeness I want to add reference to
http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection
It has more complete logic than most of others answers on this page.
However I prefer Compare-Net-Objects library
https://github.com/GregFinzer/Compare-Net-Objects (referred by Liviu Trifoi's answer)
The library has NuGet package http://www.nuget.org/packages/CompareNETObjects and multiple options to configure.
Make sure objects aren't null.
Having obj1 and obj2:
if(obj1 == null )
{
return false;
}
return obj1.Equals( obj2 );
This works even if the objects are different. you could customize the methods in the utilities class maybe you want to compare private properties as well...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class ObjectA
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public DateTime PropertyD { get; set; }
public string FieldA;
public DateTime FieldB;
}
class ObjectB
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public DateTime PropertyD { get; set; }
public string FieldA;
public DateTime FieldB;
}
class Program
{
static void Main(string[] args)
{
// create two objects with same properties
ObjectA a = new ObjectA() { PropertyA = "test", PropertyB = "test2", PropertyC = "test3" };
ObjectB b = new ObjectB() { PropertyA = "test", PropertyB = "test2", PropertyC = "test3" };
// add fields to those objects
a.FieldA = "hello";
b.FieldA = "Something differnt";
if (a.ComparePropertiesTo(b))
{
Console.WriteLine("objects have the same properties");
}
else
{
Console.WriteLine("objects have diferent properties!");
}
if (a.CompareFieldsTo(b))
{
Console.WriteLine("objects have the same Fields");
}
else
{
Console.WriteLine("objects have diferent Fields!");
}
Console.Read();
}
}
public static class Utilities
{
public static bool ComparePropertiesTo(this Object a, Object b)
{
System.Reflection.PropertyInfo[] properties = a.GetType().GetProperties(); // get all the properties of object a
foreach (var property in properties)
{
var propertyName = property.Name;
var aValue = a.GetType().GetProperty(propertyName).GetValue(a, null);
object bValue;
try // try to get the same property from object b. maybe that property does
// not exist!
{
bValue = b.GetType().GetProperty(propertyName).GetValue(b, null);
}
catch
{
return false;
}
if (aValue == null && bValue == null)
continue;
if (aValue == null && bValue != null)
return false;
if (aValue != null && bValue == null)
return false;
// if properties do not match return false
if (aValue.GetHashCode() != bValue.GetHashCode())
{
return false;
}
}
return true;
}
public static bool CompareFieldsTo(this Object a, Object b)
{
System.Reflection.FieldInfo[] fields = a.GetType().GetFields(); // get all the properties of object a
foreach (var field in fields)
{
var fieldName = field.Name;
var aValue = a.GetType().GetField(fieldName).GetValue(a);
object bValue;
try // try to get the same property from object b. maybe that property does
// not exist!
{
bValue = b.GetType().GetField(fieldName).GetValue(b);
}
catch
{
return false;
}
if (aValue == null && bValue == null)
continue;
if (aValue == null && bValue != null)
return false;
if (aValue != null && bValue == null)
return false;
// if properties do not match return false
if (aValue.GetHashCode() != bValue.GetHashCode())
{
return false;
}
}
return true;
}
}
Update on Liviu's answer above - CompareObjects.DifferencesString has been deprecated.
This works well in a unit test:
CompareLogic compareLogic = new CompareLogic();
ComparisonResult result = compareLogic.Compare(object1, object2);
Assert.IsTrue(result.AreEqual);
This method will get properties of the class and compare the values for each property. If any of the values are different, it will return false, else it will return true.
public static bool Compare<T>(T Object1, T object2)
{
//Get the type of the object
Type type = typeof(T);
//return false if any of the object is false
if (Object1 == null || object2 == null)
return false;
//Loop through each properties inside class and get values for the property from both the objects and compare
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
if (property.Name != "ExtensionData")
{
string Object1Value = string.Empty;
string Object2Value = string.Empty;
if (type.GetProperty(property.Name).GetValue(Object1, null) != null)
Object1Value = type.GetProperty(property.Name).GetValue(Object1, null).ToString();
if (type.GetProperty(property.Name).GetValue(object2, null) != null)
Object2Value = type.GetProperty(property.Name).GetValue(object2, null).ToString();
if (Object1Value.Trim() != Object2Value.Trim())
{
return false;
}
}
}
return true;
}
Usage:
bool isEqual = Compare<Employee>(Object1, Object2)
To expand on #nawfal:s answer, I use this to test objects of different types in my unit tests to compare equal property names. In my case database entity and DTO.
Used like this in my test;
Assert.IsTrue(resultDto.PublicInstancePropertiesEqual(expectedEntity));
public static bool PublicInstancePropertiesEqual<T, Z>(this T self, Z to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
var type = typeof(T);
var type2 = typeof(Z);
var ignoreList = new List<string>(ignore);
var unequalProperties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where !ignoreList.Contains(pi.Name)
let selfValue = type.GetProperty(pi.Name).GetValue(self, null)
let toValue = type2.GetProperty(pi.Name).GetValue(to, null)
where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))
select selfValue;
return !unequalProperties.Any();
}
return self == null && to == null;
}
sometimes you don't want to compare all public properties and want to compare only the subset of them, so in this case you can just move logic to compare the desired list of properties to abstract class
public abstract class ValueObject<T> where T : ValueObject<T>
{
protected abstract IEnumerable<object> GetAttributesToIncludeInEqualityCheck();
public override bool Equals(object other)
{
return Equals(other as T);
}
public bool Equals(T other)
{
if (other == null)
{
return false;
}
return GetAttributesToIncludeInEqualityCheck()
.SequenceEqual(other.GetAttributesToIncludeInEqualityCheck());
}
public static bool operator ==(ValueObject<T> left, ValueObject<T> right)
{
return Equals(left, right);
}
public static bool operator !=(ValueObject<T> left, ValueObject<T> right)
{
return !(left == right);
}
public override int GetHashCode()
{
int hash = 17;
foreach (var obj in this.GetAttributesToIncludeInEqualityCheck())
hash = hash * 31 + (obj == null ? 0 : obj.GetHashCode());
return hash;
}
}
and use this abstract class later to compare the objects
public class Meters : ValueObject<Meters>
{
...
protected decimal DistanceInMeters { get; private set; }
...
protected override IEnumerable<object> GetAttributesToIncludeInEqualityCheck()
{
return new List<Object> { DistanceInMeters };
}
}
my solution inspired from Aras Alenin answer above where I added one level of object comparison and a custom object for comparison results. I am also interested to get property name with object name:
public static IEnumerable<ObjectPropertyChanged> GetPublicSimplePropertiesChanged<T>(this T previous, T proposedChange,
string[] namesOfPropertiesToBeIgnored) where T : class
{
return GetPublicGenericPropertiesChanged(previous, proposedChange, namesOfPropertiesToBeIgnored, true, null, null);
}
public static IReadOnlyList<ObjectPropertyChanged> GetPublicGenericPropertiesChanged<T>(this T previous, T proposedChange,
string[] namesOfPropertiesToBeIgnored) where T : class
{
return GetPublicGenericPropertiesChanged(previous, proposedChange, namesOfPropertiesToBeIgnored, false, null, null);
}
/// <summary>
/// Gets the names of the public properties which values differs between first and second objects.
/// Considers 'simple' properties AND for complex properties without index, get the simple properties of the children objects.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="previous">The previous object.</param>
/// <param name="proposedChange">The second object which should be the new one.</param>
/// <param name="namesOfPropertiesToBeIgnored">The names of the properties to be ignored.</param>
/// <param name="simpleTypeOnly">if set to <c>true</c> consider simple types only.</param>
/// <param name="parentTypeString">The parent type string. Meant only for recursive call with simpleTypeOnly set to <c>true</c>.</param>
/// <param name="secondType">when calling recursively, the current type of T must be clearly defined here, as T will be more generic (using base class).</param>
/// <returns>
/// the names of the properties
/// </returns>
private static IReadOnlyList<ObjectPropertyChanged> GetPublicGenericPropertiesChanged<T>(this T previous, T proposedChange,
string[] namesOfPropertiesToBeIgnored, bool simpleTypeOnly, string parentTypeString, Type secondType) where T : class
{
List<ObjectPropertyChanged> propertiesChanged = new List<ObjectPropertyChanged>();
if (previous != null && proposedChange != null)
{
var type = secondType == null ? typeof(T) : secondType;
string typeStr = parentTypeString + type.Name + ".";
var ignoreList = namesOfPropertiesToBeIgnored.CreateList();
IEnumerable<IEnumerable<ObjectPropertyChanged>> genericPropertiesChanged =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where !ignoreList.Contains(pi.Name) && pi.GetIndexParameters().Length == 0
&& (!simpleTypeOnly || simpleTypeOnly && pi.PropertyType.IsSimpleType())
let firstValue = type.GetProperty(pi.Name).GetValue(previous, null)
let secondValue = type.GetProperty(pi.Name).GetValue(proposedChange, null)
where firstValue != secondValue && (firstValue == null || !firstValue.Equals(secondValue))
let subPropertiesChanged = simpleTypeOnly || pi.PropertyType.IsSimpleType()
? null
: GetPublicGenericPropertiesChanged(firstValue, secondValue, namesOfPropertiesToBeIgnored, true, typeStr, pi.PropertyType)
let objectPropertiesChanged = subPropertiesChanged != null && subPropertiesChanged.Count() > 0
? subPropertiesChanged
: (new ObjectPropertyChanged(proposedChange.ToString(), typeStr + pi.Name, firstValue.ToStringOrNull(), secondValue.ToStringOrNull())).CreateList()
select objectPropertiesChanged;
if (genericPropertiesChanged != null)
{ // get items from sub lists
genericPropertiesChanged.ForEach(a => propertiesChanged.AddRange(a));
}
}
return propertiesChanged;
}
Using the following class to store comparison results
[System.Serializable]
public class ObjectPropertyChanged
{
public ObjectPropertyChanged(string objectId, string propertyName, string previousValue, string changedValue)
{
ObjectId = objectId;
PropertyName = propertyName;
PreviousValue = previousValue;
ProposedChangedValue = changedValue;
}
public string ObjectId { get; set; }
public string PropertyName { get; set; }
public string PreviousValue { get; set; }
public string ProposedChangedValue { get; set; }
}
And a sample unit test:
[TestMethod()]
public void GetPublicGenericPropertiesChangedTest1()
{
// Define objects to test
Function func1 = new Function { Id = 1, Description = "func1" };
Function func2 = new Function { Id = 2, Description = "func2" };
FunctionAssignment funcAss1 = new FunctionAssignment
{
Function = func1,
Level = 1
};
FunctionAssignment funcAss2 = new FunctionAssignment
{
Function = func2,
Level = 2
};
// Main test: read properties changed
var propertiesChanged = Utils.GetPublicGenericPropertiesChanged(funcAss1, funcAss2, null);
Assert.IsNotNull(propertiesChanged);
Assert.IsTrue(propertiesChanged.Count == 3);
Assert.IsTrue(propertiesChanged[0].PropertyName == "FunctionAssignment.Function.Description");
Assert.IsTrue(propertiesChanged[1].PropertyName == "FunctionAssignment.Function.Id");
Assert.IsTrue(propertiesChanged[2].PropertyName == "FunctionAssignment.Level");
}

Convert string to nullable type (int, double, etc...)

I am attempting to do some data conversion. Unfortunately, much of the data is in strings, where it should be int's or double, etc...
So what I've got is something like:
double? amount = Convert.ToDouble(strAmount);
The problem with this approach is if strAmount is empty, if it's empty I want it to amount to be null, so when I add it into the database the column will be null. So I ended up writing this:
double? amount = null;
if(strAmount.Trim().Length>0)
{
amount = Convert.ToDouble(strAmount);
}
Now this works fine, but I now have five lines of code instead of one. This makes things a little more difficult to read, especially when I have a large amount of columns to convert.
I thought I'd use an extension to the string class and generic's to pass in the type, this is because it could be a double, or an int, or a long. So I tried this:
public static class GenericExtension
{
public static Nullable<T> ConvertToNullable<T>(this string s, T type) where T: struct
{
if (s.Trim().Length > 0)
{
return (Nullable<T>)s;
}
return null;
}
}
But I get the error: Cannot convert type 'string' to 'T?'
Is there a way around this? I am not very familiar with creating methods using generics.
Another thing to keep in mind is that the string itself might be null.
public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
Nullable<T> result = new Nullable<T>();
try
{
if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0)
{
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
result = (T)conv.ConvertFrom(s);
}
}
catch { }
return result;
}
You could try using the below extension method:
public static T? GetValueOrNull<T>(this string valueAsString)
where T : struct
{
if (string.IsNullOrEmpty(valueAsString))
return null;
return (T) Convert.ChangeType(valueAsString, typeof(T));
}
This way you can do this:
double? amount = strAmount.GetValueOrNull<double>();
int? amount = strAmount.GetValueOrNull<int>();
decimal? amount = strAmount.GetValueOrNull<decimal>();
What about this:
double? amount = string.IsNullOrEmpty(strAmount) ? (double?)null : Convert.ToDouble(strAmount);
Of course, this doesn't take into account the convert failing.
I wrote this generic type converter. It works with Nullable and standard values, converting between all convertible types - not just string. It handles all sorts of scenarios that you'd expect (default values, null values, other values, etc...)
I've been using this for about a year in dozens of production programs, so it should be pretty solid.
public static T To<T>(this IConvertible obj)
{
Type t = typeof(T);
if (t.IsGenericType
&& (t.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
if (obj == null)
{
return (T)(object)null;
}
else
{
return (T)Convert.ChangeType(obj, Nullable.GetUnderlyingType(t));
}
}
else
{
return (T)Convert.ChangeType(obj, t);
}
}
public static T ToOrDefault<T>
(this IConvertible obj)
{
try
{
return To<T>(obj);
}
catch
{
return default(T);
}
}
public static bool ToOrDefault<T>
(this IConvertible obj,
out T newObj)
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = default(T);
return false;
}
}
public static T ToOrOther<T>
(this IConvertible obj,
T other)
{
try
{
return To<T>(obj);
}
catch
{
return other;
}
}
public static bool ToOrOther<T>
(this IConvertible obj,
out T newObj,
T other)
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = other;
return false;
}
}
public static T ToOrNull<T>
(this IConvertible obj)
where T : class
{
try
{
return To<T>(obj);
}
catch
{
return null;
}
}
public static bool ToOrNull<T>
(this IConvertible obj,
out T newObj)
where T : class
{
try
{
newObj = To<T>(obj);
return true;
}
catch
{
newObj = null;
return false;
}
}
You might want to try:
TypeConverter conv = TypeDescriptor.GetConverter(typeof(int));
conv.ConvertFrom(mystring);
do your own null check and return int? if necessary. You'll also want to wrap that in a try {}
Give this a shot...
public delegate bool TryParseDelegate<T>(string data, out T output);
public static T? ToNullablePrimitive<T>(this string data,
TryParseDelegate<T> func) where T:struct
{
string.IsNullOrEmpty(data) return null;
T output;
if (func(data, out output))
{
return (T?)output;
}
return null;
}
Then call it like this...
void doStuff()
{
string foo = "1.0";
double? myDouble = foo.ToNullablePrimitive<double>(double.TryParse);
foo = "1";
int? myInt = foo.ToNullablePrimitive<int>(int.TryParse);
foo = "haha";
int? myInt2 = foo.ToNullablePrimitive<int>(int.TryParse);
}
I like Joel's answer, but I've modified it slightly as I'm not a fan of eating exceptions.
/// <summary>
/// Converts a string to the specified nullable type.
/// </summary>
/// <typeparam name="T">The type to convert to</typeparam>
/// <param name="s">The string to convert</param>
/// <returns>The nullable output</returns>
public static T? ToNullable<T>(this string s) where T : struct
{
if (string.IsNullOrWhiteSpace(s))
return null;
TypeConverter conv = TypeDescriptor.GetConverter(typeof (T));
return (T) conv.ConvertFrom(s);
}
/// <summary>
/// Attempts to convert a string to the specified nullable primative.
/// </summary>
/// <typeparam name="T">The primitive type to convert to</typeparam>
/// <param name="data">The string to convert</param>
/// <param name="output">The nullable output</param>
/// <returns>
/// True if conversion is successfull, false otherwise. Null and whitespace will
/// be converted to null and return true.
/// </returns>
public static bool TryParseNullable<T>(this string data, out T? output) where T : struct
{
try
{
output = data.ToNullable<T>();
return true;
}
catch
{
output = null;
return false;
}
}
You can use the following with objects, unfortunately this does not work with strings though.
double? amount = (double?)someObject;
I use it for wrapping a session variable in a property (on a base page).. so my actual usage is (in my base page):
public int? OrganisationID
{
get { return (int?)Session[Constants.Session_Key_OrganisationID]; }
set { Session[Constants.Session_Key_OrganisationID] = value; }
}
I'm able to check for null in page logic:
if (base.OrganisationID == null)
// do stuff
There is no way around this. Nullable, as well as your method, is constrained to using only value types as it's argument. String is a reference type and hence is incompatible with this declaration.
public static class GenericExtension
{
public static T? ConvertToNullable<T>(this String s) where T : struct
{
try
{
return (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(s);
}
catch (Exception)
{
return null;
}
}
}
There is a generic solution (for any type). Usability is good, but implementation should be improved:
http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/
This allows you to write very clean code like this:
string value = null;
int? x = value.ConvertOrDefault<int?>();
and also:
object obj = 1;
string value = null;
int x = 5;
if (value.TryConvert(out x))
Console.WriteLine("TryConvert example: " + x);
bool boolean = "false".ConvertOrDefault<bool>();
bool? nullableBoolean = "".ConvertOrDefault<bool?>();
int integer = obj.ConvertOrDefault<int>();
int negativeInteger = "-12123".ConvertOrDefault<int>();
int? nullableInteger = value.ConvertOrDefault<int?>();
MyEnum enumValue = "SecondValue".ConvertOrDefault<MyEnum>();
MyObjectBase myObject = new MyObjectClassA();
MyObjectClassA myObjectClassA = myObject.ConvertOrDefault<MyObjectClassA>();
Here's something based on accepted answer. I removed the try/catch to make sure all the exceptions are not swallowed and not dealt with. Also made sure that the return variable (in accepted answer) is never initialized twice for nothing.
public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
if (!string.IsNullOrWhiteSpace(s))
{
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(s);
}
return default(Nullable<T>);
}
My example for anonimous types:
private object ConvertNullable(object value, Type nullableType)
{
Type resultType = typeof(Nullable<>).MakeGenericType(nullableType.GetGenericArguments());
return Activator.CreateInstance(resultType, Convert.ChangeType(value, nullableType.GetGenericArguments()[0]));
}
...
Type anonimousType = typeof(Nullable<int>);
object nullableInt1 = ConvertNullable("5", anonimousType);
// or evident Type
Nullable<int> nullableInt2 = (Nullable<int>)ConvertNullable("5", typeof(Nullable<int>));
Another variation. This one
Does not swallow exceptions
Throws a NotSupportedException if the type can not be converted from string. For instance, a custom struct without a type converter.
Otherwise returns a (T?)null if the string fails to parse. No need to check for null or whitespace.
using System.ComponentModel;
public static Nullable<T> ToNullable<T>(this string s) where T : struct
{
var ret = new Nullable<T>();
var conv = TypeDescriptor.GetConverter(typeof(T));
if (!conv.CanConvertFrom(typeof(string)))
{
throw new NotSupportedException();
}
if (conv.IsValid(s))
{
ret = (T)conv.ConvertFrom(s);
}
return ret;
}
Let's add one more similar solution to the stack. This one also parses enums, and it looks nice. Very safe.
/// <summary>
/// <para>More convenient than using T.TryParse(string, out T).
/// Works with primitive types, structs, and enums.
/// Tries to parse the string to an instance of the type specified.
/// If the input cannot be parsed, null will be returned.
/// </para>
/// <para>
/// If the value of the caller is null, null will be returned.
/// So if you have "string s = null;" and then you try "s.ToNullable...",
/// null will be returned. No null exception will be thrown.
/// </para>
/// <author>Contributed by Taylor Love (Pangamma)</author>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="p_self"></param>
/// <returns></returns>
public static T? ToNullable<T>(this string p_self) where T : struct
{
if (!string.IsNullOrEmpty(p_self))
{
var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if (converter.IsValid(p_self)) return (T)converter.ConvertFromString(p_self);
if (typeof(T).IsEnum) { T t; if (Enum.TryParse<T>(p_self, out t)) return t;}
}
return null;
}
https://github.com/Pangamma/PangammaUtilities-CSharp/blob/master/PangammaUtilities/Extensions/ToNullableStringExtension.cs
The generic answer provided by "Joel Coehoorn" is good.
But, this is another way without using those GetConverter... or try/catch blocks... (i'm not sure but this may have better performance in some cases):
public static class StrToNumberExtensions
{
public static short ToShort(this string s, short defaultValue = 0) => short.TryParse(s, out var v) ? v : defaultValue;
public static int ToInt(this string s, int defaultValue = 0) => int.TryParse(s, out var v) ? v : defaultValue;
public static long ToLong(this string s, long defaultValue = 0) => long.TryParse(s, out var v) ? v : defaultValue;
public static decimal ToDecimal(this string s, decimal defaultValue = 0) => decimal.TryParse(s, out var v) ? v : defaultValue;
public static float ToFloat(this string s, float defaultValue = 0) => float.TryParse(s, out var v) ? v : defaultValue;
public static double ToDouble(this string s, double defaultValue = 0) => double.TryParse(s, out var v) ? v : defaultValue;
public static short? ToshortNullable(this string s, short? defaultValue = null) => short.TryParse(s, out var v) ? v : defaultValue;
public static int? ToIntNullable(this string s, int? defaultValue = null) => int.TryParse(s, out var v) ? v : defaultValue;
public static long? ToLongNullable(this string s, long? defaultValue = null) => long.TryParse(s, out var v) ? v : defaultValue;
public static decimal? ToDecimalNullable(this string s, decimal? defaultValue = null) => decimal.TryParse(s, out var v) ? v : defaultValue;
public static float? ToFloatNullable(this string s, float? defaultValue = null) => float.TryParse(s, out var v) ? v : defaultValue;
public static double? ToDoubleNullable(this string s, double? defaultValue = null) => double.TryParse(s, out var v) ? v : defaultValue;
}
Usage is as following:
var x1 = "123".ToInt(); //123
var x2 = "abc".ToInt(); //0
var x3 = "abc".ToIntNullable(); // (int?)null
int x4 = ((string)null).ToInt(-1); // -1
int x5 = "abc".ToInt(-1); // -1
var y = "19.50".ToDecimal(); //19.50
var z1 = "invalid number string".ToDoubleNullable(); // (double?)null
var z2 = "invalid number string".ToDoubleNullable(0); // (double?)0

Categories