29 October 2012

C# extension - Parse to decimal regardless of regional settings

A problem that often comes up is that decimal numbers are wrongly parsed on different computers due to the regional settings. The following extensions are intended to ensure that a string is correctly parsed to a decimal, regardless of the decimal separator used by the system.

Parse

The first extension returns a string that can be correctly parsed to a decimal type.
/// <summary>
/// Parses a string that is supposed to be a decimal number in
/// such a way that it can be parsed to a decimal data type.
/// </summary>
/// <param name="source">The string to be parsed.</param>
/// <returns>A string that can be parsed to a decimal data type.</returns>
public static string ParseDecimalString(this string source) {
  if (!source.HasValue()) {
    return "0";
  }
  else {
    int indexLastSep = source.LastIndexOfAny(new char[] { '.', ',' });
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < source.Length; i++) {
      if (char.IsDigit(source[i]))
        result.Append(source[i]);
      else if (i == indexLastSep)
        result.Append(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
      else if (i == 0 && source[i] == '-')
        result.Append('-');
    }
    return result.ToString();
  }
}

Cast

The second extension does the casting. I separated this one from the parsing for reusability.
/// <summary>
/// Converts from string to decimal. Returns 0m on failure.
/// </summary>
/// <param name="source">The string.</param>
/// <returns>A decimal representing the string or 0m on failure.</returns>
public static decimal ToDecimal(this string source) {
  decimal result = 0m;
  decimal.TryParse(source.ParseDecimalString(), out result);
  return result;
}

25 October 2012

Extension - Strip a string

One day I wrote this convienient extension that removes letters, digits and/or symbols - as specified - from a string:
/// <summary>Removes characters of specified types.</summary>
/// <param name="source">The string to remove from.</param>
/// <param name="removeTypes">A string containing 'L' to remove letters, 'D' to remove digits and 'S' to remove symbols.</param>
/// <returns>A string containing the remaining characters.</returns>
public static string Strip(this string source, string removeTypes) {
  bool letters = !string.IsNullOrEmpty(removeTypes) && removeTypes.Contains('L');
  bool digits = !string.IsNullOrEmpty(removeTypes) && removeTypes.Contains('D');
  bool symbols = !string.IsNullOrEmpty(removeTypes) && removeTypes.Contains('S');

  StringBuilder result = new StringBuilder();
  if (!string.IsNullOrEmpty(source)) {
    foreach (char c in source) {
      if (char.IsLetter(c)) {
        if (!letters) result.Append(c);
      }
      else if (char.IsDigit(c)) {
        if (!digits) result.Append(c);
      }
      else {
        if (!symbols) result.Append(c);
      }
    }
  }
  return result.ToString();
}
Note that the line removeTypes.Contains(char) relies on System.Linq.

13 June 2012

SharePoint - Access the object model from a custom web service

I ran into a serious issue yesterday. I had built a custom web service to access a list on our SharePoint site, and everything seemed to work fine. But when I was not logged in, the site kept asking for my credentials and the line where I accessed the list threw a 401 - unauthorized. I tried to get to the list using SPContext, but even with RunWithElevatedPrivileges around it, it wouldn't work. The only thing I could do with SPContext however was get the GUID of the site and web that contained my list. So I got both of these and used them to gain access to my list like this:
SPSecurity.RunWithElevatedPrivileges(delegate() {
  using (SPSite spSite = new SPSite(new Guid("846ca17c-b8eb-4b04-8888-f5b7a1c6cfa3"))) {
    using (SPWeb web = spSite.OpenWeb(new Guid("14ba40e8-ee72-40fe-8b98-d1b1f72355aa"))) {
      list = web.Lists["Kalender"];
    }
  }
});
And surprise: this works!

31 May 2012

Math - Scaling a value

Sometimes you have this thing where you have two ranges, and you need to scale a value from the one to the other; e.g.:
Range 1: 0.....x.....100   x=50
Range 2: 0.....y.....500   y=?
Thus:
100 > 500
 50 >   ?
  x >   y

C# code

Thus, I want to know the value of y. I wrote this extension to get it:
internal static double Scale(this double value, double maxValue, double maxScale) {
  if (maxValue == 0 || maxScale == 0)
    return 0;
  else if (maxValue == maxScale)
    return value;
  else
    return value / (maxValue / maxScale);
}

result = 50.Scale(100, 500); //Result will be 250

Try it


if (max. value)equals (max. scale)
then (value)is (result)
...

See also

Interpolating a value

29 May 2012

.NET - get assembly attributes

Referencing assembly attributes

In .NET, when you go to the properties of a project and select Application > Assembly Information, you can fill in some basic information about the application you're making. It would be convenient if you could reference these fields from within your code, to avoid having to duplicate this information. There is a fairly easy way to do this. To get the company:

public static string Company {
  get {
    object[] attr = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
    if (attr == null || attr.Length <= 0)
      return string.Empty;
    else
      return (attr[0] as AssemblyCompanyAttribute).Company;
  }
}

This can now be written shorter. To get the title:

private static string GetTitle() => Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyTitleAttribute>()?.Title;

I put this as static properties in the Program class. That way I can reference these fields anywere I need them.

Using them in XAML

One useful purpose for this is setting the window title of a WPF application. To do this, you need to declare the namespace of the application in XAML. By convention, it's tag is xmlns:local. Then you can simply write:

Title="{x:Static local:App.Title}"

Assuming you have a method that retrieves the AssemblyTitleAttribute in the App class, the window will now display this title. Also note that the method has to be public for this.

24 April 2012

C# - Define an operator on a struct

Sometimes a struct comes in handy, as it is a value type that cannot be NULL. You can't however write things like a == b on them; that is unless you actualy define what == means for that struct. Take the following struct:
public struct IdName {
  public int Id { get; set; }
  public string Name { get; set; }
}
I simply tell it what == means, but watch out for null's. The compiler will also require that you define !=:
public static bool operator ==(IdName a, IdName b) {
  if ((object)a == null && (object)b == null) return true;
  else if ((object)a != null && (object)b != null) return a.Id == b.Id && a.Name == b.Name;
  else return false;
}
public static bool operator !=(IdName a, IdName b) {
  return !(a == b);
}
Compiling that will give you two warnings: you did not override GetHashCode() nor Equals(). These are necessary to get the underlying infrastructure to work well with the new type. So, implementing the latter should be easy:
public override bool Equals(object obj) {
  if (obj != null && obj is IdName)
    return ((IdName)obj).Id == Id && ((IdName)obj).Name == Name;
  else
    return false;
}
And the hashcode thing:
public override int GetHashCode() {
  return base.GetHashCode() ^ Id;
}
And now you can write a == b on structs, just like you can with integers and such.

01 February 2012

C# - == vs. .Equals()

I used to think that strA.Equals(strB) is faster than strA == strB, so I always used it. But that's not entirely accurate.

== is the identity test. It checks wheather two objects are one and the same. This is the faster of the two.
.Equals() asks one object to compare it's value against another and decide whether or not they are equal.

Since value types are kept on the stack, and not on the heap, they can only be compared by value. The ValueType-base class uses reflection to compare each property. Value types, like structs, should therefore override .Equals() and == to speed things up.

One last consideration is that strA.Equals(strB) requires strA to be an instantiated object, whereas strA == strB allows strA to be NULL.

Conclusion: comparing two strings using == is the same as doing it with .Equals().

09 January 2012

JSON - Parse a JSON date to a JS date

When a date is returned via JSON, it's written like this:
/Date(1326063600000)/
To convert this to a JavaScript Date, you parse it as follows:
new Date(parseInt(json.substr(6)))