KC.Ricochet

Package Description


Keywords
License
Unlicense
Install
Install-Package KC.Ricochet -Version 4.3.1

Documentation

Ricochet

This is a library for a few simple fast reflection operations. It's largely used for automagically copying properties and fields between similar types (ie copying from EntityFramework models to Web Controller models). There is also a bit of functionality for marking types with attributes, or ignoring them.

Installing

  • .Net Framework: Install-Package KC.Ricochet
  • .Net Core: dotnet add package KC.Ricochet

Getting Started

using System;
using System.Linq;
using KC.Ricochet;

namespace Example.Ricochet
{
    class Program
    {
        static void Main(string[] args)
        {
            var dbModel = new DatabaseModel() {
                Id = 1,
                Name = "Bob",
                Date = DateTime.UtcNow
            };
            var webModel = new WebModel();

            //Copy all public properties from the dbModel to the webModel ignoring the case of the property name
            KC.Ricochet.Util.CopyPublicValueProps(fromT: dbModel, toU: webModel, ignoreCase: true, copyNullMembers: true);

            //Copy all public properties from another webModel to the dbModel, ignoring case, and not copying any properties which are set to null.
            var userModifiedWebModel = new WebModel() {
                id = 1,
                name = "Bob Belcher"
            };

            KC.Ricochet.Util.CopyPublicValueProps(fromT: userModifiedWebModel, toU: dbModel, ignoreCase: true, copyNullMembers: false);
            //You could then save the dbModel, knowing only user specified (non-null) items were changed.

            //You can implement your own functions like the above. This is how the Copy function was implemented:
            void CopyPublicValueProps<T, U>(T fromT, U toU, bool ignoreCase = true, bool copyNullMembers = false) where T : class where U : class {
                Copy(fromT, toU, x => x.IsPublic && x.IsValueOrString && x.IsProperty, ignoreCase, copyNullMembers);
            }

            void Copy<T, U>(T fromT, U toU, Func<PropertyAndFieldAccessor, bool> predicate = null, bool ignoreCase = true, bool copyNullMembers = false) where T : class where U : class {
                var fromProps = Util.GetPropsAndFields<T>();
                var toProps = Util.GetPropsAndFields<U>();
                if (predicate != null) {
                    fromProps = fromProps.Where(predicate);
                    toProps = toProps.Where(predicate);
                }

                foreach (var toProp in toProps) {
                    var fromProp = fromProps.FirstOrDefault(x => string.Compare(x.Name, toProp.Name, ignoreCase) == 0);
                    if (fromProp == null) {
                        continue;
                    }

                    var fromValue = fromProp.GetVal(fromT);
                    if (!copyNullMembers && object.Equals(fromValue, null)) {
                        continue;
                    }

                    toProp.SetVal(toU, fromValue);
                }
            }

            //You can also get members which you've marked:
            var nameMembers = KC.Ricochet.Util.GetPropsAndFields<WebModel>(x => x.Markers.Contains("IsAName"));
            //See class definition below with RicochetMark attribute.
            //This allows you to implement special logic with marked members.

            //There's also functionality for creating objects.
            //This is less useful unless you're building your own dependency injection or something:
            var withAType = KC.Ricochet.Util.GetConstructor<DatabaseModel>(typeof(int)).New(6);
            var withoutAType = KC.Ricochet.Util.GetConstructor(typeof(DatabaseModel), typeof(int)).New(7);
        }
    }

    class DatabaseModel {
        public DatabaseModel() { }
        public DatabaseModel(int i) { }

        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Date { get; set; }
        public string SecretData { get; set; }
    }

    class WebModel {
        public int id { get; set; }
        [RicochetMark("IsAName")]
        public string name { get; set; }
        public DateTime? date { get; set; }
        [RicochetIgnore] //Ensure that this secret data must be manually copied into a WebModel.
        public string secretData { get; set; }
    }
}