Generi c Property Setter для Generi c Введите C# Класс - PullRequest
0 голосов
/ 23 апреля 2020

Я пытаюсь в общем случае установить значения полей в классе ItemsRow (и других аналогичных по формату, но свойства и поля различны.

Я хочу сделать что-то похожее на то, что я делаю с жестким кодированием

public Dictionary<object, Action<T, object>> SetFieldValues = new Dictionary<object, Action<T, object>>
{
 {"Description", (m,v) => m.Description = (string)v};
}


public class Mapping<T> where T:Row
{


public Dictionary<object, Action<T, object>> SetFieldValues(string[] headers)
{
        Dictionary<object, Action<T, object>> myDict = new Dictionary<object, Action<T, object>>();

        //  Activator 
        var objectType = typeof(T); // Type.GetType(T);

        var tRow = Activator.CreateInstance(objectType) as Row;

        foreach (var item in headers)
        {
            var myfield = tRow.FindFieldByPropertyName(item);
            //myDict[item] = myfield = 
            //myDict[item] = (m, v) => m.FindFieldByPropertyName(item) = (Type.GetType(myfield.Type.ToString()))v;
        }

         // I want this to be dynamic header[i],(m,v) => m.(property to set for object) = (cast to type m.property type)v
        //{"ItemName", (m,v) => m.ItemName = (string)v},
        //{"Description", (m,v) => m.Description = (string)v},



        return myDict;

}

// Имена классов будут разными, свойства и поля будут разными ..

  public sealed class ItemsRow : Row
   {

        public String ItemName
        {
            get { return Fields.ItemName[this]; }
            set { Fields.ItemName[this] = value; }
        }

        public String Description
        {
            get { return Fields.Description[this]; }
            set { Fields.Description[this] = value; }
        }


        public static readonly RowFields Fields = new RowFields().Init();

        public ItemsRow()
            : base(Fields)
        {
        }

        public class RowFields : RowFieldsBase
        {
            public StringField ItemName;
            public StringField Description;
    }
}

Базовый класс

======== ================================================== =======================

using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;

namespace Serenity.Data
{
    [JsonConverter(typeof(JsonRowConverter))]
    public abstract partial class Row : IEntityWithJoins, 
        INotifyPropertyChanged, IEditableObject
#if !COREFX
        , IDataErrorInfo
#endif
    {
        internal RowFieldsBase fields;
        internal bool[] assignedFields;
        internal Hashtable dictionaryData;
        internal bool ignoreConstraints;
        internal object[] indexedData;
        internal bool tracking;
        internal bool trackWithChecks;

        protected Row(RowFieldsBase fields)
        {
            if (fields == null)
                throw new ArgumentNullException("fields");

            this.fields = fields.InitInstance(this);

            TrackAssignments = true;
        }

        public void CloneInto(Row clone, 
            bool cloneHandlers)
        {
            clone.ignoreConstraints = ignoreConstraints;

            foreach (var field in GetFields())
                field.Copy(this, clone);

            clone.tracking = tracking;
            if (tracking)
            {
                if (assignedFields != null)
                {
                    clone.assignedFields = new bool[assignedFields.Length];
                    Array.Copy(assignedFields, clone.assignedFields, assignedFields.Length);
                }
            }
            else
                clone.assignedFields = null;

            clone.trackWithChecks = trackWithChecks;

            clone.originalValues = originalValues;

            if (dictionaryData != null)
                clone.dictionaryData = (Hashtable)this.dictionaryData.Clone();
            else
                clone.dictionaryData = null;

            if (indexedData != null)
            {
                clone.indexedData = new object[indexedData.Length];
                for (var i = 0; i < indexedData.Length; i++)
                    clone.indexedData[i] = indexedData[i];
            }
            else
                clone.indexedData = null;

            if (previousValues != null)
                clone.previousValues = previousValues.CloneRow();
            else
                clone.previousValues = null;

            if (cloneHandlers)
            {
                clone.postHandler = this.postHandler;
                clone.propertyChanged = this.propertyChanged;

                if (this.validationErrors != null)
                    clone.validationErrors = new Dictionary<string, string>(this.validationErrors);
                else
                    clone.validationErrors = null;
            }
        }

        public Row CloneRow()
        {
            var clone = CreateNew();
            CloneInto(clone, true);
            return clone;
        }

        public virtual Row CreateNew()
        {
            if (fields.rowFactory == null)
                throw new NotImplementedException();

            return fields.rowFactory();
        }

        internal void FieldAssignedValue(Field field)
        {
            if (assignedFields == null)
                assignedFields = new bool[fields.Count];

            assignedFields[field.index] = true;

            if (validationErrors != null)
                RemoveValidationError(field.PropertyName ?? field.Name);

            if (propertyChanged != null)
            {
                if (field.IndexCompare(previousValues, this) != 0)
                {
                    RaisePropertyChanged(field);
                    field.Copy(this, previousValues);
                }
            }
        }

        public Field FindField(string fieldName)
        {
            return fields.FindField(fieldName);
        }

        public Field FindFieldByPropertyName(string propertyName)
        {
            return fields.FindFieldByPropertyName(propertyName);
        }

        public RowFieldsBase GetFields()
        {
            return fields;
        }

        public int FieldCount
        {
            get { return fields.Count; }
        }

        public bool IsAnyFieldAssigned
        {
            get
            {
                return tracking && assignedFields != null;
            }
        }

        public bool IgnoreConstraints
        {
            get { return ignoreConstraints; }
            set { ignoreConstraints = value; }
        }

        public string Table
        {
            get { return fields.TableName; }
        }

        public bool TrackAssignments
        {
            get
            { 
                return tracking;
            }
            set 
            {
                if (tracking != value)
                {
                    if (value)
                    {
                        if (propertyChanged != null)
                            previousValues = this.CloneRow();

                        tracking = value;
                    }
                    else
                    {
                        tracking = false;
                        trackWithChecks = false;
                        assignedFields = null;
                    }
                }
            }
        }

        public bool TrackWithChecks
        {
            get 
            {
                return tracking && trackWithChecks;
            }
            set
            {
                if (value != TrackWithChecks)
                {
                    if (value && !tracking)
                        TrackAssignments = true;

                    trackWithChecks = value;
                }
            }
        }

        private Field FindFieldEnsure(string fieldName)
        {
            var field = FindField(fieldName);
            if (ReferenceEquals(null, field))
                throw new ArgumentOutOfRangeException("fieldName", String.Format(
                    "{0} has no field with name '{1}'.", this.GetType().Name, fieldName));
            return field;
        }

        public object this[string fieldName]
        {
            get 
            {
                var field = FindFieldByPropertyName(fieldName) ??
                    FindField(fieldName);

                if (ReferenceEquals(null, field))
                {
                    if (dictionaryData != null)
                        return dictionaryData[fieldName];

                    return null;
                }

                return field.AsObject(this); 
            }
            set
            {
                (FindFieldByPropertyName(fieldName) ?? 
                    FindFieldEnsure(fieldName)).AsObject(this, value);
            }
        }

        public void SetDictionaryData(object key, object value)
        {
            if (value == null)
            {
                if (dictionaryData == null)
                    return;
                dictionaryData[key] = null;
            }
            else
            {
                if (dictionaryData == null)
                    dictionaryData = new Hashtable();
                dictionaryData[key] = value;
            }
        }

        public object GetDictionaryData(object key)
        {
            if (dictionaryData != null)
                return dictionaryData[key];

            return null;
        }


        internal void SetIndexedData(int index, object value)
        {
            if (value == null)
            {
                if (indexedData == null)
                    return;

                indexedData[index] = null;
            }
            else
            {
                if (indexedData == null)
                    indexedData = new object[this.FieldCount];

                indexedData[index] = value;
            }
        }

        internal object GetIndexedData(int index)
        {
            if (indexedData != null)
                return indexedData[index];

            return null;
        }

        public bool IsAssigned(Field field)
        {
            if (assignedFields == null)
                return false;

            return assignedFields[field.index];
        }

        public void ClearAssignment(Field field)
        {
            if (assignedFields == null)
                return;

            assignedFields[field.index] = false;

            for (var i = 0; i < assignedFields.Length; i++)
                if (assignedFields[i])
                    return;

            assignedFields = null;
        }

        public bool IsAnyFieldChanged
        {
            get
            {
                if (originalValues == null)
                    return false;

                for (var i = 0; i < fields.Count; i++)
                    if (fields[i].IndexCompare(originalValues, this) != 0)
                        return true;

                return false;
            }
        }

        IDictionary<string, Join> IHaveJoins.Joins
        {
            get { return fields.Joins; }
        }
    }
}

1 Ответ

1 голос
/ 24 апреля 2020

Извините, я не смог вернуться к вам вчера, но обещание - это обещание :). И во время написания этого кода я начал сомневаться в том, как на самом деле выглядят ваши заголовки. Как вы собираетесь определить, какое свойство принадлежит какому заголовку? Если у вас нет какого-либо типа распознавания того, чего я, возможно, упускаю из вашего кода.

Но общая идея такова:

Конечно, это основано на предпосылке, что заголовки являются ключевыми значениями пар какой ключ является идентификатором, какое свойство использовать.

static void Main(string[] args)
{
    var values = new Dictionary<string, string>()
    {
        ["Title"] = "Test",
        ["Amount"] = "5",
        ["Description"] = "Some description"
    };

    var target = new TestClass();
    var setters = GetPropertySetters(target);

    foreach(KeyValuePair<string, string> value in values)
    {
        if (setters.ContainsKey(value.Key))
            setters[value.Key].Invoke(value.Value);
    }

    Console.WriteLine(JsonConvert.SerializeObject(target));
    Console.ReadLine();
}

public static Dictionary<string, Action<string>> GetPropertySetters<T>(T source)
{
    var result = new Dictionary<string, Action<string>>(StringComparer.OrdinalIgnoreCase);

    foreach (PropertyInfo pi in typeof(T).GetProperties())
        result.Add(pi.Name, (string value) => { pi.SetValue(source, Convert.ChangeType(value, pi.PropertyType)); });

    return result;
}

public class TestClass
{
    public string Title { get; set; }
    public int Amount { get; set; }
    public string Description { get; set; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...