2

I have a system with few model classes, each one with another members, but the behavior of all models are same-

For example, all models are request input from user in this format: Hi, Please enter {MemberName} value as {MemberType}: And convert the input to MemberType.

Because this intended to be library, I want that in each model I can to access his members (or members-like) at compile time, not by myModel.get("memberName"), but rather by myModel.memberName or myModel.get(modelEnum.MemberName) or myModel.ListOfMember[0] or maybe Factory.getMember(myModel, SpecificModelMembersList[0]) etc..

I don't need to add or remove members in runtime, just create a good way to add them in compile time, and not change all the code for add member to model class.

How would you design it?

I work with C#.

Thank you and you can suggest an english fixes.

baruchiro
  • 5,088
  • 5
  • 44
  • 66

1 Answers1

2

My idea is to use lambda expressions to get access to property info data in a simple and intuitive way (with IntelliSense support and all refactorings available). The code demonstrating the approach is below.

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleAppTest2
{
    class Program
    {
        static void Main(string[] args)
        {
            var myModel = new MyModel();

            var cmb = ConsoleModelBuilder<MyModel>.RequestFromComsole(myModel)
                .FillProp(x=>x.MethodName)
                .FillProp(x => x.Birthday);
            Console.ReadLine();
        }
    }

    internal class MyModel
    {
        public int MethodName { get; set; }
        public DateTime Birthday { get; set; }

    }

    internal class ConsoleModelBuilder<T>
    {
        public T Model { get; private set; }

        public static ConsoleModelBuilder<T> RequestFromComsole(T obj)
        {
            return new ConsoleModelBuilder<T>() { Model = obj };


        }

        public ConsoleModelBuilder<T> FillProp<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
        {
            PropertyInfo info = GetPropertyInfo(Model, propertyLambda);

            Console.WriteLine($"Hi, Please enter {info.Name} value as {info.PropertyType.Name}:");
            //Code to parse console input and fill property of Model
            return this;
        }


        public PropertyInfo GetPropertyInfo<TSource, TProperty>(
    TSource source,
    Expression<Func<TSource, TProperty>> propertyLambda)
        {
            Type type = typeof(TSource);

            MemberExpression member = propertyLambda.Body as MemberExpression;
            if (member == null)
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a method, not a property.",
                    propertyLambda.ToString()));

            PropertyInfo propInfo = member.Member as PropertyInfo;
            if (propInfo == null)
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a field, not a property.",
                    propertyLambda.ToString()));

            if (type != propInfo.ReflectedType &&
                !type.IsSubclassOf(propInfo.ReflectedType))
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a property that is not from type {1}.",
                    propertyLambda.ToString(),
                    type));

            return propInfo;
        }
    }
}

Core method to get access to PropertyInfo is from the StackOverflow question Retrieving Property name from lambda expression.

Sergey Prosin
  • 711
  • 4
  • 11