Lightsoffnow t Www h Reviews s Www tsearchr Choice e Lightsoffnow rsearcha Www o Travel l Sickness Www r Quality p Definition r Reviews i Reviews ssearch searcha Tag esearch Quality asearchusearch Sickness n
Www Travel a Quality searchs 2011 asearchc Reviews e Reviews esearchr Tag ha a Lightsoffnow auaai Tag y a Lightsoffnow ea
c Tag c
e Tag rc Lightsoffnow i searchww e searchig Travel Quality cawsearchH Lightsoffnow gh Travel Www Tr0v Definition l
Lightsoffnow T Travel av High l Sickness saa0csearchh 2011 Ww Lightsoffnow .
It can also convert to string implicitly. Then you can use it as string. Or you can make it looks like the type of parameter is Enumeration but not string.
TranslateClient client = new TranslateClient(); string translated = client.Translate(text, Language.ChineseSimplified, Language.English);
It looks the same of the old enum parameter version. But the Language is not a enum but a subclass of Enumeration and the English is a public static readonly field.
public static readonly Language English = new Language("English", "en");
Here I want add two more static method and a implicit convert method.
public static Language GetDefault(); public static ICollection<Language> GetEnums(); public static implicit operator Language(string value)
It’s not hard using reflection. But I need repeat them in every subclasses of Enumeration.
Although code template tool can help me a lot, but I do not think it’s a good I idea. Don’t repeat yourself!
So I create a generic Enumeration class:
public abstract class Enumeration<T> : Enumeration, IEquatable<T> where T : Enumeration<T>
This class has a very interesting constrain. We can only create a subclass like this:
public sealed class SortType : Enumeration<SortType>
The subclass must pass itself as the generic parameter. (Tell me if I’m wrong.) In other words, the T in Enumeration is must be the type of subclass.
Here I marked SortType as sealed, because the Enumeration can only know it subclass but not sub-subclass.
Here is the whole code of Enumeration:
/// <summary>
/// The enumeration. Provide more static methods and properties for every concrete enumeration.
/// </summary>
/// <typeparam name="T">The type of concrete enumeration.</typeparam>
public abstract class Enumeration<T> : Enumeration, IEquatable<T>
where T : Enumeration<T>
{}
/// <summary>
/// Initializes a new instance of the <see cref="Enumeration<T>"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="value">The value.</param>
protected Enumeration(string name, string value)
: base(name, value)
{}
/// <summary>
/// Initializes a new instance of the <see cref="Enumeration<T>"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="value">The value.</param>
/// <param name="isDefault">if set to <c>true</c> it is default value.</param>
protected Enumeration(string name, string value, bool isDefault)
: base(name, value, isDefault)
{}
/// <summary>
/// Gets the dictionary of value and enumeration.
/// </summary>
/// <value>The dictionary.</value>
protected static IDictionary<string, T> Dictionary
{}
}
/// <summary>
/// Gets the default enumeration.
/// </summary>
/// <returns>The default enumeration</returns>
public static T GetDefault()
{}
/// <summary>
/// Gets all enumerations.
/// </summary>
/// <returns>All enumerations</returns>
public static ICollection<T> GetEnums()
{}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(T other)
{}
return this.Value == other.Value;
}
/// <summary>
/// Initializes this instance.
/// </summary>
protected static void Initialize()
{}
}
}
}
/// <summary>
/// Converts the specified value to this enumeration.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="construct">The constructor function.</param>
/// <returns>The enumeration.</returns>
protected static T Convert(string value, Func<string, T> construct)
{}
T @enum;
if (!Dictionary.TryGetValue(value, out @enum))
{}
return @enum;
}
}
Here I use the lazy load trick but not initialize in the static constructor, because the static constructor will run before than the static fields in subclass have been assigned.
And the implement convert operation can only defined in the subclass. So I put most of the logic into the Convert method.
Here is what a subclass looks like:
/// <summary>
/// The search safety level.
/// </summary>
public sealed class SafeLevel : Enumeration<SafeLevel>
{}
private SafeLevel(string name, string value)
: base(name, value)
{}
private SafeLevel(string name, string value, bool isDefault)
: base(name, value, isDefault)
{}
/// <summary>
/// Performs an implicit conversion from <see cref="System.String"/> to <see cref="SafeLevel"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SafeLevel(string value)
{}
}
Although the solution has some smell, like visit static method in superclass and static protected method.
I hope it can solve my problem well.
Thanks for reading.
What’s the tail recursion?
In computer science, tail recursion (or tail-end recursion) is a special case of recursion in which the last operation of the function, the tail call, is a recursive call. Such recursions can be easily transformed to iterations. Replacing recursion with iteration, manually or automatically, can drastically decrease the amount of stack space used and improve efficiency. This technique is commonly used with functional programming languages, where the declarative approach and explicit handling of state promote the use of recursive functions that would otherwise rapidly fill the call stack. (from pedia)
Still don’t understand? OK, let me show you the code.
int f(int n) {}
If you run f(0), you will get a StackOverFlowException.
How about F#?
let rec f n = f (n + 1)
The keyword “rec” tell compiler it’s a recursive function.
We use Reflector to see how it looks like as a C# code:
public static a f<a>(int n)
{}
}
The magic the compiler done is called Tail Call Optimization. (see Adventures in F#–Tail Recursion in Three Languages)
Another case of tail recursion:
type t() = member x.f1 n = x.f2 (n + 1) member x.f2 n = x.f1 (n + 1)
This time, when you run t().f1 0, you will get the StackOverFlowException too.
Don’t worry. Just open the F# project properties dialog and the Build tab. Check the “Generate tail calls” on. Then the exception disappeared.
See what’s different of the IL code:
“Generate tail calls” unchecked
.method public instance !!a f1(int32 n) cil managed {}
“Generate tail calls” checked
.method public instance !!a f1(int32 n) cil managed {}
One more case:
type t() = member x.f3 n = x.f3 (n + 1)
No matter you check the “Generate tail calls” or not, the compiler will do the Tail Call Optimization.
The reflector will render it like this:
public a f3&amp;lt;a&amp;gt;(int n)
{}
}
Scala compile will do the Tail Call Optimization too, but there’s no “tail” in JVM until now. So we need to wait for the Java 7.