Поле переопределения не работает [дубликат]

Для конкретной ситуации, когда вы хотите сделать что-то в стиле Makefile, перезаписывая файл назначения на основе исходного файла, только если исходный файл является более новым, я придумал этот отвратительный, но простой метод. Это только вариант, если вы никоим образом не беспокоитесь о существующем содержимом целевого файла, который старше исходного файла.

  для / f "delims =" %% r in  ('xcopy / D / Y / f / e "% inputdir% \% source_filename%" "% outputdir% \% dest_filename%"') do (IF "%% r" EQU "1 Файл скопирован"% build_command  %!% inputdir% \% source_filename% ""% outputdir% \% dest_filename% ")  

Что это такое, xcopy только перезаписывает файл назначения, если исходный файл более новый. Если оно не новее, %% r «Скопировано 0 файлов», поэтому условная команда не выполняется, а целевой файл никогда не перезаписывается. Если он новее, %% r «Скопирован 1 файл (ы)», поэтому ваш файл назначения вкратце является копией исходного файла, затем выполняется команда сборки, заменяя его новой версией того,

Возможно, я должен был просто написать скрипт perl.

(Примечание: вы также можете xcopy обрабатывать ситуацию, в которой место назначения файл изначально не существует, поместив звездочку в конец имени файла назначения, если вы этого не сделаете, тогда xcopy не уверен, является ли назначение именем файла или папки, и там не имеет значения по умолчанию для ответа на имя файла.)

9
задан pacu 29 November 2011 в 15:54
поделиться

3 ответа

Вы можете настроить валидаторы и метаданные из своего конкретного класса, но в решении есть несколько движущихся частей, в том числе два пользовательских поставщика метаданных.

Сначала создайте пользовательский Attribute, чтобы украсить каждый свойство базового класса. Это необходимо как флаг для наших заказных поставщиков, чтобы указать, когда необходим дальнейший анализ. Это атрибут:

[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class BaseTypeAttribute : Attribute { }

Затем создайте пользовательский ModelMetadataProvider, наследующий от DataAnnotationsModelMetadataProvider:

public class MyModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(
        IEnumerable<Attribute> attributes,
        Type containerType,
        Func<object> modelAccessor,
        Type modelType,
        string propertyName)
    {
        var attribute = attributes.FirstOrDefault(a => a.GetType().Equals(typeof(BaseTypeAttribute))) as BaseTypeAttribute;
        if (attribute != null && modelAccessor != null)
        {
            var target = modelAccessor.Target;
            var containerField = target.GetType().GetField("container");
            if (containerField == null)
            {
                var vdi = target.GetType().GetField("vdi").GetValue(target) as ViewDataInfo;
                var concreteType = vdi.Container.GetType();
                return base.CreateMetadata(attributes, concreteType, modelAccessor, modelType, propertyName);
            }
            else
            {
                var container = containerField.GetValue(target);
                var concreteType = container.GetType();
                var propertyField = target.GetType().GetField("property");
                if (propertyField == null)
                {
                    concreteType = base.GetMetadataForProperties(container, containerType)
                        .FirstOrDefault(p => p.PropertyName == "ConcreteType").Model as System.Type;
                    if (concreteType != null)
                        return base.GetMetadataForProperties(container, concreteType)
                            .FirstOrDefault(pr => pr.PropertyName == propertyName);
                }
                return base.CreateMetadata(attributes, concreteType, modelAccessor, modelType, propertyName);
            }
        }
        return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
    }
}

Затем создайте пользовательский ModelValidatorProvider, наследующий от DataAnnotationsModelValidatorProvider:

public class MyModelMetadataValidatorProvider : DataAnnotationsModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        List<ModelValidator> vals = base.GetValidators(metadata, context, attributes).ToList();

        var baseTypeAttribute = attributes.FirstOrDefault(a => a.GetType().Equals(typeof(BaseTypeAttribute))) 
            as BaseTypeAttribute;

        if (baseTypeAttribute != null)
        {
            // get our parent model
            var parentMetaData = ModelMetadataProviders.Current.GetMetadataForProperties(context.Controller.ViewData.Model,
                metadata.ContainerType);

            // get the concrete type
            var concreteType = parentMetaData.FirstOrDefault(p => p.PropertyName == "ConcreteType").Model;
            if (concreteType != null)
            {
                var concreteMetadata = ModelMetadataProviders.Current.GetMetadataForProperties(context.Controller.ViewData.Model,
                    Type.GetType(concreteType.ToString()));

                var concretePropertyMetadata = concreteMetadata.FirstOrDefault(p => p.PropertyName == metadata.PropertyName);

                vals = base.GetValidators(concretePropertyMetadata, context, attributes).ToList();
            }
        }
        return vals.AsEnumerable();
    }
}

После этого зарегистрируйте оба пользовательских поставщика в Application_Start в Global.asax.cs:

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new MvcApplication8.Controllers.MyModelMetadataValidatorProvider());
ModelMetadataProviders.Current = new MvcApplication8.Controllers.MyModelMetadataProvider();

Теперь измените свои модели следующим образом:

public class Person
{
    public Type ConcreteType { get; set; }

    [Required]
    [Display(Name = "Full name")]
    [BaseType]
    public string FullName { get; set; }

    [Display(Name = "Address Line 1")]
    [BaseType]
    public virtual string Address1 { get; set; }
}

public class Sender : Person
{
    public Sender()
    {
        this.ConcreteType = typeof(Sender);
    }

    [Required]
    [Display(Name = "Address Line One")]
    public override string Address1 { get; set; }
}

public class Receiver : Person
{
}

Обратите внимание, что базовый класс имеет новое свойство, ConcreteType. Это будет использоваться для указания того, какой класс наследования создавал этот базовый класс. Всякий раз, когда наследующий класс имеет метаданные, которые переопределяют метаданные в базовом классе, конструктор наследующего класса должен установить свойство ConcreteType базового класса.

Теперь, даже если ваше представление использует базовый класс, атрибуты, специфичные для любой конкретный класс наследования появится в вашем представлении и повлияет на валидацию модели.

Кроме того, вы должны иметь возможность превратить View в шаблон для типа Person и использовать шаблон для любой экземпляр, использующий базовый класс или наследующий его.

8
ответ дан counsellorben 15 August 2018 в 22:33
поделиться
  • 1
    var propertyField = target.GetType (). GetField ("свойство"); Для чего эта линия? – Sergey 8 November 2015 в 18:28
  • 2
    И что для target.GetType (). GetField (& quot; vdi & quot;) – Sergey 8 November 2015 в 19:47

Считаете ли вы, что вы создаете свой собственный шаблон EditorTemplate для лица, отправителя и получателя? EditorFor и DisplayFor ищут настраиваемый шаблон, соответствующий типу объекта.

Внутренний метод будет искать шаблон, соответствующий типу объекта. Затем он будет искать шаблон, соответствующий базовому классу, а затем по цепочке наследования.

0
ответ дан Nick Bork 15 August 2018 в 22:33
поделиться
  • 1
    Да, но в моем случае различия между Sender и Receiver не значительны, поэтому я не думаю, что есть смысл иметь один и тот же взгляд дважды только ради изменения директивы @model в верхней части. – pacu 29 November 2011 в 19:53

Хмм, это сложно, так как метод HtmlHelper<T>.EditorFor использует общий параметр HtmlHelper<T>, чтобы выяснить, какие атрибуты проверки необходимы.

Я бы предложил написать собственный метод EditorFor extension что делегаты обращаются к не-универсальному методу HtmlHelper.Editor.

1
ответ дан Rich O'Kelly 15 August 2018 в 22:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: