Skip to content

Commit

Permalink
Fix PromoteType and check/promote only the needed value.
Browse files Browse the repository at this point in the history
  • Loading branch information
304NotModified committed Oct 29, 2016
1 parent 04cdd0b commit 96331de
Showing 1 changed file with 122 additions and 40 deletions.
162 changes: 122 additions & 40 deletions src/NLog/Conditions/ConditionRelationalExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ namespace NLog.Conditions
{
using System;
using System.Globalization;
using System.Collections.Generic;
using NLog.Common;

/// <summary>
/// Condition relational (<b>==</b>, <b>!=</b>, <b>&lt;</b>, <b>&lt;=</b>,
Expand Down Expand Up @@ -133,75 +135,155 @@ private static object Compare(object leftValue, object rightValue, ConditionRela
}
}

private static void PromoteTypes(ref object val1, ref object val2)
/// <summary>
/// Dictionary from type to index. Lower index should be tested first.
/// </summary>
private static Dictionary<System.Type, int> TypePromoteOrder = BuildTypeOrderDictionary();

private static Dictionary<System.Type, int> BuildTypeOrderDictionary()
{
if (val1 == null || val2 == null)
var list = new List<Type>
{
return;
typeof(DateTime),
typeof(double),
typeof(float),
typeof(decimal),
typeof(long),
typeof(int),
typeof(bool),
typeof(string),
};

var dict = new Dictionary<Type, int>(list.Count);
for (int i = 0; i < list.Count; i++)
{
dict.Add(list[i], i);
}
return dict;

}

if (val1.GetType() == val2.GetType())
private static void PromoteTypes(ref object val1, ref object val2)
{
if (val1 == null || val2 == null)
{
return;
}

if (val1 is DateTime || val2 is DateTime)
var type1 = val1.GetType();
var type2 = val2.GetType();
if (type1 == type2)
{
val1 = Convert.ToDateTime(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToDateTime(val2, CultureInfo.InvariantCulture);
return;
}

if (val1 is string || val2 is string)
//types are not equal
var type1Order = GetOrder(type1);
var type2Order = GetOrder(type2);

if (type1Order < type2Order)
{
val1 = Convert.ToString(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToString(val2, CultureInfo.InvariantCulture);
return;
// first try promote val 2 with type 1
if (TryPromoteValues(ref val2, ref val1, type2, type1)) return;
}

if (val1 is double || val2 is double)
else
{
val1 = Convert.ToDouble(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToDouble(val2, CultureInfo.InvariantCulture);
return;
// first try promote val 1 with type 2
if (TryPromoteValues(ref val1, ref val2, type1, type2)) return;
}

if (val1 is float || val2 is float)
throw new ConditionEvaluationException("Cannot find common type for '" + type1.Name + "' and '" + type2.Name + "'.");
}

private static bool TryPromoteValues(ref object val1, ref object val2, Type type1, Type type2)
{
//promote val 1 with type 2
if (TryPromoteValue(ref val1, type2))
{
val1 = Convert.ToSingle(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToSingle(val2, CultureInfo.InvariantCulture);
return;
return true;
}

if (val1 is decimal || val2 is decimal)
//promote val 2 with type 1
if (TryPromoteValue(ref val2, type1))
{
val1 = Convert.ToDecimal(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToDecimal(val2, CultureInfo.InvariantCulture);
return;
return true;
}
return false;
}

if (val1 is long || val2 is long)
private static int GetOrder(Type type1)
{
int index;
var success = TypePromoteOrder.TryGetValue(type1, out index);
if (success)
{
val1 = Convert.ToInt64(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToInt64(val2, CultureInfo.InvariantCulture);
return;
return index;
}
//not found, try as last
return int.MaxValue;
}

if (val1 is int || val2 is int)
/// <summary>
/// Promoto <paramref name="val"/> to type
/// </summary>
/// <param name="val"></param>
/// <param name="type1"></param>
/// <returns>success?</returns>
private static bool TryPromoteValue(ref object val, Type type1)
{
try
{
val1 = Convert.ToInt32(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToInt32(val2, CultureInfo.InvariantCulture);
return;
if (type1 == typeof(DateTime))
{
val = Convert.ToDateTime(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(double))
{
val = Convert.ToDouble(val, CultureInfo.InvariantCulture);
return true;
}
if (type1 == typeof(float))
{
val = Convert.ToSingle(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(decimal))
{
val = Convert.ToDecimal(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(long))
{
val = Convert.ToInt64(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(int))
{
val = Convert.ToInt32(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(bool))
{
val = Convert.ToBoolean(val, CultureInfo.InvariantCulture);
return true;
}

if (type1 == typeof(string))
{
val = Convert.ToString(val, CultureInfo.InvariantCulture);
return true;
}
}

if (val1 is bool || val2 is bool)
catch (Exception)
{
val1 = Convert.ToBoolean(val1, CultureInfo.InvariantCulture);
val2 = Convert.ToBoolean(val2, CultureInfo.InvariantCulture);
return;
InternalLogger.Debug("converion of {0} to {1} failed", val, type1.Name);
}

throw new ConditionEvaluationException("Cannot find common type for '" + val1.GetType().Name + "' and '" + val2.GetType().Name + "'.");
return false;
}

private string GetOperatorString()
Expand Down

0 comments on commit 96331de

Please sign in to comment.