Абстрагируйте тип в статическом методе в нестатическом классе

У меня есть такой класс:

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);
    }
}

Я хочу абстрагироваться от линии

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

Я хочу сделать этот класс независимым от типа i18n. Я хочу иметь возможность указать тип для менеджера ресурсов при построении/инициализации, сделать класс более универсальным и поместить его в отдельную библиотеку классов.

Каковы мои варианты? Можно ли это сделать со статическим классом или мне нужен нестатический класс? Или я могу просто оставить все как есть, абстрагировать rm как поле класса и инициализировать его в конструкторе?

Спасибо

ОБНОВЛЕНИЕ. Обратите внимание, что класс, скорее всего, будет использоваться на различных сайтах ASP.NET MVC в global.asax.cs, например:

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

На самом деле я никогда не ссылаюсь на этот класс и не использую его напрямую, ASP.NET MVC делает все «под капотом».


person mare    schedule 24.08.2011    source источник
comment
Какое преимущество это имеет перед простым наличием DisplayAttribute объявлений свойств модели с указанным типом ресурса и именем ресурса (при условии, что DisplayAttribute работает правильно для используемой вами структуры (например, это работает нормально в MVC3, но не в MVC2))   -  person Russ Cam    schedule 24.08.2011
comment
огромное преимущество, потому что это позволяет нам вообще пропустить DisplayAttribute и по умолчанию использовать этот поставщик метаданных модели для предоставления строк ресурсов - я считаю, что написание атрибутов, особенно тех, которые содержат ссылки на имена ресурсов, занимает очень много времени. И это работает отлично, теперь я просто хотел бы сделать его более общим   -  person mare    schedule 24.08.2011


Ответы (2)


Вы можете сделать класс универсальным:

    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);
    }

И настроить так:

ModelMetadataProviders.Current = new LocalizedDataAnnotationsModelMetadataProvider<i18n>();
person Femaref    schedule 24.08.2011
comment
это может сработать, но проверьте обновленный код, который я предоставил, где я подключаю класс к текущему ModelMetaDataProvider. Я должен каким-то образом ввести Т-типа в класс. - person mare; 24.08.2011
comment
Я обновил ваш код дополнительными модификациями, чтобы код был полным. Поскольку вы направили меня в правильном направлении, я принимаю ваш ответ. - person mare; 24.08.2011

Предполагая, что тип i18n согласован во всем приложении, у вас есть несколько вариантов, которые являются формами инверсии управления / внедрения зависимостей. Самое простое сделать что-то вроде этого:

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);
    }
}

Где I18nTypeProvider.GetI18nType — это еще один статический метод в другом месте, который имеет логику для поиска соответствующего типа и возврата его во время выполнения (т. е. отражение).

Еще лучшим вариантом является использование продукта внедрения зависимостей, такого как Managed Extensibility Framework или NInject.

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

http://ninject.org/

person Samuel Neff    schedule 24.08.2011