mare
mare

Reputation: 13083

Abstract away the type in a static method in a non-static class

I have a class like this:

public class LocalizedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
                                                    Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var meta = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        if (string.IsNullOrWhiteSpace(propertyName))
            return meta;
        if (meta.DisplayName == null)
            GetLocalizedDisplayName(meta, propertyName);
        if (string.IsNullOrWhiteSpace(meta.DisplayName))
        {
            string resource = string.Format("{0}_{1}", meta.ContainerType.Name, meta.PropertyName).ToLower();
            meta.DisplayName = string.Format("[{0}]", resource);
        }
        return meta;
    }

    private static void GetLocalizedDisplayName(ModelMetadata meta, string propertyName)
    {
        ResourceManager rm = new ResourceManager(typeof (i18n));
        CultureInfo culture = Thread.CurrentThread.CurrentUICulture;
        string resource = string.Format("{0}_{1}", meta.ContainerType.Name, meta.PropertyName).ToLower();
        meta.DisplayName = rm.GetString(resource, culture);
    }
}

I want to abstract away the line

ResourceManager rm = new ResourceManager(typeof (i18n));

I want to make this class indenpendent of the type i18n. I want to be able to specify the type for the resource manager at construction/initialization, making the class more universal and put it in a standalone class library.

What are my options? Can it be done with a static class or do I have to have non-static class? Or can I just leave the way it is, abstract the rm as class field and initialize it in the constructor?

Thank you

UPDATE: Please note the class will most likely be used in various ASP.NET MVC sites in global.asax.cs like this:

protected override void OnApplicationStarted()
{
    base.OnApplicationStarted();
    ModelMetadataProviders.Current = new LocalizedDataAnnotationsModelMetadataProvider();
}

I am never actually referencing or using this class directly, ASP.NET MVC does everything under the hood.

Upvotes: 0

Views: 261

Answers (2)

Femaref
Femaref

Reputation: 61437

You can make the class generic:

    public class LocalizedDataAnnotationsModelMetadataProvider<T> : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
                                                    Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var meta = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        if (string.IsNullOrWhiteSpace(propertyName))
            return meta;
        if (meta.DisplayName == null)
            GetLocalizedDisplayName<T>(meta, propertyName);
        if (string.IsNullOrWhiteSpace(meta.DisplayName))
        {
            string resource = string.Format("{0}_{1}", meta.ContainerType.Name, meta.PropertyName).ToLower();
            meta.DisplayName = string.Format("[{0}]", resource);
        }
        return meta;
    }

    private static void GetLocalizedDisplayName<T>(ModelMetadata meta, string propertyName)
    {
        ResourceManager rm = new ResourceManager(typeof (T));
        CultureInfo culture = Thread.CurrentThread.CurrentUICulture;
        string resource = string.Format("{0}_{1}", meta.ContainerType.Name, meta.PropertyName).ToLower();
        meta.DisplayName = rm.GetString(resource, culture);
    }

And set it up like this:

ModelMetadataProviders.Current = new LocalizedDataAnnotationsModelMetadataProvider<i18n>();

Upvotes: 4

Samuel Neff
Samuel Neff

Reputation: 74909

Assuming type i18n is consistent across the entire application, then you have a few options, which all are forms of Inversion of Control / Dependency Injections. The simplest thing is to do something like this:

public class LocalizedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private static readonly Type _i18nType = I18nTypeProvider.GetI18nType();

    private static void GetLocalizedDisplayName(ModelMetadata meta, string propertyName)
    {
        ResourceManager rm = new ResourceManager(_i18nType);
        CultureInfo culture = Thread.CurrentThread.CurrentUICulture;
        string resource = string.Format("{0}_{1}", meta.ContainerType.Name, meta.PropertyName).ToLower();
        meta.DisplayName = rm.GetString(resource, culture);
    }
}

Where I18nTypeProvider.GetI18nType is another static method elsewhere that has the logic to find the appropriate type and return it at runtime (i.e., reflection).

An even better option is to use an dependency injection product like Managed Extensibility Framework or NInject.

http://msdn.microsoft.com/en-us/magazine/ee291628.aspx

http://ninject.org/

Upvotes: 0

Related Questions