0

I would like to know if it's possible to create a method that will update a property/field via reflection simply by passing in the names of the property/field to set, i.e.

IFTDGN.Set( "S009", "E1001", "B" );

Where S009 is a field contained within the IFTDGN class, and E1001 is a field/property accessed through the S009 field, and finally B is the value I want to put into the E1001 property/field.

I have this code (to make it easy to reproduce):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EDIDemo
{
    using System.Reflection;

    class Program
    {
        static void Main( string[] args )
        {
            IFTDGN iftdgn = new IFTDGN();
            iftdgn.S009.E1001.Set( "A" );
            iftdgn.S009.E1002.Set( "CC" );

            iftdgn.Set( "S009", "E1001", "B" );

            Console.WriteLine( iftdgn.CreateMessage() );
            Console.ReadKey();
        }
    }

    /// <summary>
    ///  Represents an International Forwarding and Transport Dangerous Goods Notification message 
    /// </summary>
    class IFTDGN : EDIMessage
    {
        public S009 S009 = new S009();

        public IFTDGN()
            : base()
        {
            base.RegisterMessage( this.GetType().Name );
        }

        public override string CreateMessage()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine( "S009" );
            sb.AppendFormat( "\t{0} {1}\n", "E1001", S009.E1001.Code.Tag );
            sb.AppendFormat( "\t{0} {1}\n", "E1002", S009.E1002.Code.Tag );

            return sb.ToString();
        }

        public override void Set( string segment, string element, string code )
        {
            // *** THIS IS THE BIT I AM HAVING TROUBLE WITH **
            var fi_seg = this.GetType().GetFields().FirstOrDefault( p => p.Name == segment );
            var pi_elem = fi_seg.GetType().GetProperties().FirstOrDefault( p => p.Name == element );
        }

    }

    class S009
    {
        protected IDictionary<String, EDIDataElement> Elements = new Dictionary<String, EDIDataElement>()
        {
            { "E1001", new E1001() },
            { "E1002", new E1002() }
        };

        public E1001 E1001 { get { return (E1001)Elements[ "E1001" ]; } }
        public E1002 E1002 { get { return (E1002)Elements[ "E1002" ]; } }
    }

    abstract class EDIMessage
    {
        protected String MessageID;

        protected EDIMessage()
        { }

        protected void RegisterMessage( String messageID )
        {
            this.MessageID = messageID;
        }

        public virtual void Set( String segment, String element, String code )
        {
            throw new NotImplementedException();
        }

        public abstract String CreateMessage();

    }

    abstract class EDIDataElement
    {
        public Code Code { get; private set; }

        public virtual bool Mandatory
        {
            get
            {
                return false;
            }
        }

        protected IList<Code> Codes = new List<Code>();
        protected String ElementID;

        public virtual void Set( String code )
        {
            if ( !Codes.Any( c => c.Tag == code ) )
                throw new Exception( "Code '" + code + "' not found for element '" + ElementID + "'" );

            this.Code = Codes.FirstOrDefault( c => c.Tag == code );
        }

        protected void RegisterElement( String elementID )
        {
            this.ElementID = elementID;
        }

    }

    class E1001 : EDIDataElement
    {
        public E1001()
            : base()
        {
            base.Codes.Add( new Code( "A", "Code A" ) );
            base.Codes.Add( new Code( "B", "Code B" ) );
            base.Codes.Add( new Code( "C", "Code C" ) );
            base.Codes.Add( new Code( "D", "Code D" ) );
            base.Codes.Add( new Code( "E", "Code E" ) );

            base.RegisterElement( this.GetType().Name );
        }

        public override void Set( String code )
        {
            base.Set( code );
        }

        public override bool Mandatory
        {
            get
            {
                return true;
            }
        }

    }

    class E1002 : EDIDataElement
    {
        public E1002()
            : base()
        {
            base.Codes.Add( new Code( "AA", "Code AA" ) );
            base.Codes.Add( new Code( "BB", "Code BB" ) );
            base.Codes.Add( new Code( "CC", "Code CC" ) );
            base.Codes.Add( new Code( "DD", "Code DD" ) );
            base.Codes.Add( new Code( "EE", "Code EE" ) );

            base.RegisterElement( this.GetType().Name );

        }

        public override void Set( String code )
        {
            base.Set( code );
        }

        public override bool Mandatory
        {
            get
            {
                return true;
            }
        }

    }

    class Code
    {
        public string Tag { get; protected set; }
        public string Name { get; protected set; }

        public Code( string tag, string name )
        {
            Tag = tag;
            Name = name;
        }
    }

}

Basically, I want the pi_elem variable to contain the PropertyInfo or FieldInfo for the E1001 referenced property/field, but it always returns null.

Intrepid
  • 2,781
  • 2
  • 29
  • 54
  • possible duplicate of [How to set object property through Reflection](http://stackoverflow.com/questions/5370641/how-to-set-object-property-through-reflection) – Jon B Dec 06 '12 at 14:05
  • That is looking for properties in the original class. I am looking at accessing properties & fields further down another level. – Intrepid Dec 06 '12 at 14:08
  • It’s still the same thing, except that you first get the property of the first type and then do the setting on the resulting object. – poke Dec 06 '12 at 14:14
  • @poke: If `fi_seg` gives me a `FieldInfo` object for the `S009` field, how comes 'pi_elem' returns null when trying to get the `PropertyInfo` for the enclosed `E1001' property? – Intrepid Dec 06 '12 at 14:18
  • I guess fi_seg is of type FieldInfo, it does not have any "E1001" property. You should look at the target type. – jbl Dec 06 '12 at 14:21
  • I don't know if this is for the sake of exercise, but aren't you better off using a Dictionary? – CodeCaster Dec 06 '12 at 14:24
  • @CodeCaster@ I am using a Dictionary in the `S009` class, and using properties to return the underlying object instance using the name as the key, i.e. `E1001`. The issue I am having is that reflection cannot see the properties referenced through the `IFTDGN.S009` field. – Intrepid Dec 06 '12 at 14:29

1 Answers1

1

I guess

 var pi_elem = fi_seg.GetType().GetProperties().FirstOrDefault( p => p.Name == element );

might be :

 var pi_elem = fi_seg.FieldType.GetProperties().FirstOrDefault( p => p.Name == element );
jbl
  • 15,179
  • 3
  • 34
  • 101