public virtual void ApplyResources(object value, string objectName, CultureInfo?culture)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (objectName == null)
{
throw new ArgumentNullException(nameof(objectName));
}
if (culture == null)
{
culture = CultureInfo.CurrentUICulture;
}
// The general case here will be to always use the same culture, so optimize for
// that. The resourceSets hashtable uses culture as a key. It's value is
// a sorted dictionary that contains ALL the culture values (so it traverses up
// the parent culture chain) for that culture. This means that if ApplyResources
// is called with different cultures there could be some redundancy in the
// table, but it allows the normal case of calling with a single culture to
// be much faster.
//
// The reason we use a SortedDictionary here is to ensure the resources are applied
// in an order consistent with codedom deserialization.
SortedList <string, object?>?resources;
if (_resourceSets == null)
{
_resourceSets = new Hashtable();
resources = FillResources(culture, out ResourceSet? dummy);
_resourceSets[culture] = resources;
}
else
{
resources = (SortedList <string, object?>?)_resourceSets[culture];
if (resources == null || (resources.Comparer.Equals(StringComparer.OrdinalIgnoreCase) != IgnoreCase))
{
resources = FillResources(culture, out ResourceSet? dummy);
_resourceSets[culture] = resources;
}
}
BindingFlags flags = BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance;
if (IgnoreCase)
{
flags |= BindingFlags.IgnoreCase;
}
bool componentReflect = false;
if (value is IComponent)
{
ISite?site = ((IComponent)value).Site;
if (site != null && site.DesignMode)
{
componentReflect = true;
}
}
foreach (KeyValuePair <string, object?> kvp in resources)
{
// See if this key matches our object.
string key = kvp.Key;
if (IgnoreCase)
{
if (string.Compare(key, 0, objectName, 0, objectName.Length, StringComparison.OrdinalIgnoreCase) != 0)
{
continue;
}
}
else
{
if (string.CompareOrdinal(key, 0, objectName, 0, objectName.Length) != 0)
{
continue;
}
}
// Character after objectName.Length should be a "." or a '-', or else we should continue.
int idx = objectName.Length;
if (key.Length <= idx || (key[idx] != '.' && key[idx] != '-'))
{
continue;
}
// Bypass type descriptor if we are not in design mode. TypeDescriptor does an attribute
// scan which is quite expensive.
string propName = key.Substring(idx + 1);
if (componentReflect)
{
PropertyDescriptor?prop = TypeDescriptor.GetProperties(value).Find(propName, IgnoreCase);
if (prop != null && !prop.IsReadOnly && (kvp.Value == null || prop.PropertyType.IsInstanceOfType(kvp.Value)))
{
prop.SetValue(value, kvp.Value);
}
}
else
{
PropertyInfo?prop = null;
try
{
prop = value.GetType().GetProperty(propName, flags);
}
catch (AmbiguousMatchException)
{
// Looks like we ran into a conflict between a declared property and an inherited one.
// In such cases, we choose the most declared one.
Type?t = value.GetType();
do
{
prop = t.GetProperty(propName, flags | BindingFlags.DeclaredOnly);
t = t.BaseType;
} while (prop == null && t != null && t != typeof(object));
}
if (prop != null && prop.CanWrite && (kvp.Value == null || prop.PropertyType.IsInstanceOfType(kvp.Value)))
{
prop.SetValue(value, kvp.Value, null);
}
}
}
}