Динамические объекты с BreezeSharp

Я работаю над проектом, который требует работы с динамическими объектами с BreezeSharp. Я получаю структуру своих объектов через файл JSON, такой как:

[{
    name: 'Admin',
    serviceAddress: 'http://abcd.com/breeze/admins',
    dataProperties: {
    Id: { type: breeze.DataType.Int32 },
    Title: { nullable: true },
    ContentTypeId: {},
    Created: { type: breeze.DataType.DateTime },
    Modified: { type: breeze.DataType.DateTime },
    File: { complexType: 'Document:#File' },
},
{
    name: 'Car',
    serviceAddress: 'http://abcd.com/breeze/cars',
    dataProperties: {
    Id: { type: breeze.DataType.Int32 },
    Model: { nullable: true },
    Created: { type: breeze.DataType.DateTime },
    Modified: { type: breeze.DataType.DateTime },
}]

и я хочу автоматически генерировать объекты, которые наследуются от Breeze.Sharp.BaseEntity с перечисленными свойствами.

Мне также нужно будет создать менеджер сущностей Breeze после создания динамического объекта.

Причина, по которой мне это нужно, заключается в том, что у меня есть приложение SharePoint, которое использует BreezeJS. Сущности основаны на файле JSON.

Поэтому я хочу создать приложение для рабочего стола, которое будет использовать те же объекты на основе файла JSON. Я не уверен, что возможно создавать динамические объекты, которые наследуют класс BaseEntity.

1 ответ

Решение

Да, это возможно, но вам нужно немного поработать и написать код. Вот идея (не проверенная):

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

public class DynamicBreezeEntity : BaseEntity, IDynamicMetaObjectProvider
{
    private readonly Dictionary<string, PropertyDefinition> _properties;

    public DynamicBreezeEntity ()
    {
        _properties = new Dictionary<string, PropertyDefinition>();
    }

    public void DefineProperty(string name, Type type, bool isNullable = false)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");

        if (_properties.ContainsKey(name))
            throw new ArgumentException("Property already defined.", "name");

        if (type == null)
            throw new ArgumentNullException("type");

        if (isNullable && !type.IsValueType)
            throw new ArgumentException("Only value types can be nullable.", "type");            

        if (isNullable)
        {
            type = Nullable.GetUnderlyingType(type);
            if (type.IsValueType)
                type = typeof(Nullable<>).MakeGenericType(type);
        }

        _properties.Add(name, new PropertyDefinition { Type = type });
    }

    public object GetValue(string name)
    {
        PropertyDefinition def;
        if (_properties.TryGetValue(name, out def))
            return def.Value;

        throw new ArgumentException("Property not defined.", "name");
    }

    public void SetValue(string name, object value)
    {
        // more work todo here: handle value == null correctly

        PropertyDefinition def;
        if (_properties.TryGetValue(name, out def) && def.Type.IsAssignableFrom(value.GetType()))            
            def.Value = value;

        throw new ArgumentException("Property not defined.", "name");
    }

    public IEnumerable<string> GetPropertyNames()
    {
        return _properties.Keys.ToList();
    }

    DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
    {
        return new Proxy(this);
    }   

    private class PropertyDefinition
    {
        public Type Type { get; set; }

        public object Value { get; set; }
    }

    private class Proxy : DynamicMetaObject 
    {
         public Proxy(DynamicBreezeEntity host, Expression expression)
             : this(host, expression, BindingRestrictions.Empty) { }

         public Proxy(DynamicBreezeEntity host, Expression expression, BindingRestrictions restrictions)
             : base(expressiom restrictions, host) { }

         private DynamicBreezeEntity Host
         {
             get { return (DynamicBreezeEntity)Value; }
         }

         private BindingRestrictions GetBindingRestrictions()
         {
             var restrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType);
             return restrictions.Merge(BindingRestrictions.GetInstanceRestriction(this.Expression, this.Host));            
         }

         public override IEnumerable<string> GetDynamicMemberNames()
         {
             return this.Host.GetPropertyNames();
         }

         public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
         {
            var arguments = new Expression[] { Expression.Constant(binder.Name) };
            var method = typeof(DynamicBreezeEntity).GetMethod("GetValue");

            var callExpression = Expression.Convert(Expression.Call(Expression.Convert(this.Expressiom, this.LimitType), method, arguments), binder.ReturnType);
            return new DynamicMetaObject(callExpression, GetBindingRestrictions());
         }

         public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
         {
             var arguments = new Expression[] {
                 Expression.Constant(binder.Name),
                 Expression.Convert(value.Expression, typeof(object))
             };
             var method = typeof(DynamicBreezeEntity).GetMethod("SetValue");
             return new DynamicMetaObject(
                 Expression.Call(Expression.Convert(this.Expression, this.LimitType), method, arguments),
                 this.GetBindingRestrictions()
             );
         }
    }
}

Я не знаю, Бриз, BaseEntity Может иметь абстрактные свойства / методы, которые вам нужно реализовать. Я не сосредоточился на этом.

Вы можете использовать сейчас как

var breeze = new DynamicBreezeEntity();
breeze.DefineProperty("Id", typeof(Int32));

dynamic dynBreeze = breeze;
dynBreeze.Id = "Foo";

Console.WriteLine("Id: {0}", dynBreeze.Id);

Код, вероятно, не завершен (в настоящее время не имеет доступа к VS), но должен указывать правильное направление.

Другие вопросы по тегам