#if SYSTEM_WEB
using System.Web;
#else
using System.ComponentModel.DataAnnotations.Resources;
#endif
using System.Globalization;
using System.Reflection;
namespace System.ComponentModel.DataAnnotations {
///
/// A helper class for providing a localizable string property.
/// This class is currently compiled in both System.Web.dll and System.ComponentModel.DataAnnotations.dll.
///
internal class LocalizableString {
#region Member fields
private string _propertyName;
private string _propertyValue;
private Type _resourceType;
private Func _cachedResult;
#endregion
#region All Constructors
///
/// Constructs a localizable string, specifying the property name associated
/// with this item. The value will be used
/// within any exceptions thrown as a result of localization failures.
///
/// The name of the property being localized. This name
/// will be used within exceptions thrown as a result of localization failures.
public LocalizableString(string propertyName) {
this._propertyName = propertyName;
}
#endregion
#region Properties
///
/// Gets or sets the value of this localizable string. This value can be
/// either the literal, non-localized value, or it can be a resource name
/// found on the resource type supplied to .
///
public string Value {
get {
return this._propertyValue;
}
set {
if (this._propertyValue != value) {
this.ClearCache();
this._propertyValue = value;
}
}
}
///
/// Gets or sets the resource type to be used for localization.
///
public Type ResourceType {
get {
return this._resourceType;
}
set {
if (this._resourceType != value) {
this.ClearCache();
this._resourceType = value;
}
}
}
#endregion
#region Methods
///
/// Clears any cached values, forcing to
/// perform evaluation.
///
private void ClearCache() {
this._cachedResult = null;
}
///
/// Gets the potentially localized value.
///
///
/// If has been specified and is not
/// null, then localization will occur and the localized value will be returned.
///
/// If is null then will be returned
/// as a literal, non-localized string.
///
///
///
/// Thrown if localization fails. This can occur if has been
/// specified, is not null, but the resource could not be
/// accessed. must be a public class, and
/// must be the name of a public static string property that contains a getter.
///
///
/// Returns the potentially localized value.
///
public string GetLocalizableValue() {
if (this._cachedResult == null) {
// If the property value is null, then just cache that value
// If the resource type is null, then property value is literal, so cache it
if (this._propertyValue == null || this._resourceType == null) {
this._cachedResult = () => this._propertyValue;
} else {
// Get the property from the resource type for this resource key
PropertyInfo property = this._resourceType.GetProperty(this._propertyValue);
// We need to detect bad configurations so that we can throw exceptions accordingly
bool badlyConfigured = false;
// Make sure we found the property and it's the correct type, and that the type itself is public
if (!this._resourceType.IsVisible || property == null || property.PropertyType != typeof(string)) {
badlyConfigured = true;
} else {
// Ensure the getter for the property is available as public static
MethodInfo getter = property.GetGetMethod();
if (getter == null || !(getter.IsPublic && getter.IsStatic)) {
badlyConfigured = true;
}
}
// If the property is not configured properly, then throw a missing member exception
if (badlyConfigured) {
string exceptionMessage = String.Format(CultureInfo.CurrentCulture,
#if SYSTEM_WEB
SR.GetString(SR.LocalizableString_LocalizationFailed),
#else
DataAnnotationsResources.LocalizableString_LocalizationFailed,
#endif
this._propertyName, this._resourceType.FullName, this._propertyValue);
this._cachedResult = () => { throw new InvalidOperationException(exceptionMessage); };
} else {
// We have a valid property, so cache the resource
this._cachedResult = () => (string)property.GetValue(null, null);
}
}
}
// Return the cached result
return this._cachedResult();
}
#endregion
}
}