none
I need help with a problem using TypeDescriptor.GetConverter(propertyType) and ConvertFrom() RRS feed

  • Question

  • I have an extension that is supose to autointialize an object from a DataRow. It is to find a public property with
    the same name as the column name, sync types and set the custom object's property from the DataRow value.

    The following line in the extension throws an error on every type except string:
        // Convert the row value to the property type.
        var data = converter.ConvertFrom(rowValue);

    Extension is processing all public properties of the custom object by reflection. Since not all properties are in the
    DataRowthose will throw an (ArgumentException) error which acceptable and handled by the ignoreException boolean. This
    tests out correctly. It is when the DataRow column matches the custom objects public propery where the thrown error is
    the problem.

    I cannot get enums or any other type but strings to work. I have included my test cases, the extension code and the
    custom class with no methods. I shorten the custom class just enough to allow it to create properly for the test harness
    to use but still allow anyone to figure out what the object is doing and use othe properties while figuring out what
    is wrong.

    I have an overload for this extension that uses two objects of the same schema. That extension works just fine.

    There is a lot here but I did not want to leave anything out that might help.

        // Test class initialize
        [ClassInitialize]
        public static void MyClassInitialize(TestContext testContext)
        {
            // Use the MakeTable function below to create a new table.
            _table = MakeDataTable();
    
            // Once a table has been created, use the NewRow to create a DataRow.
            var row = _table.NewRow();
    
            // Then add the new row to the collection.
            row["BoeRaceHeader"] = "John";
            row["HeaderType"] = HeaderRaceType.Totals;
            row["OutputOrder"] = 2;
            _table.Rows.Add(row);
        }
    
        // Make the DataTable (See test class initialize)
        private static DataTable MakeDataTable()
        {
             // Create a new DataTable titled 'Names.'
            var namesTable = new DataTable("BoeData");
            // Add three column objects to the table.
            var boeRaceHeaderColumn = new DataColumn
                {
                    DataType = Type.GetType("System.String"),
                    ColumnName = "BoeRaceHeader",
                    DefaultValue = "TestRaceHeader"
                };
            namesTable.Columns.Add(boeRaceHeaderColumn);
    
            var headerTypeColumn = new DataColumn
                {
                    DataType = Type.GetType("System.Enum"),
                    ColumnName = "HeaderType",
                    DefaultValue = HeaderRaceType.Race
                };
            namesTable.Columns.Add(headerTypeColumn);
    
            var outputOrderColumn = new DataColumn
                {
                    DataType = Type.GetType("System.Decimal"),
                    ColumnName = "OutputOrder",
                    DefaultValue = (Decimal)1
                };
            namesTable.Columns.Add(outputOrderColumn);
                
            // Return the new DataTable.
            return namesTable;
            }
    
        // Testing of AutoInitialize(row)
        [TestMethod]
        public void AutoInitializeTest()
        {
            var source = new Boe(); 
            var row = _table.Rows[0]; 
            source.AutoInitialize(row);
            Assert.AreEqual(source.BoeRaceHeader, row["BoeRaceHeader"]);
            Assert.AreEqual(source.HeaderType, row["HeaderType"]);
            Assert.AreEqual(source.OutputOrder, row["OutputOrder"]);
        }
    
    
    // Extensions being tested. Overload to AutoInitialize<T>(this T source, DataRow row, BindingFlags flags, bool ignoreException)
    
        /// <summary>
        /// Auto initialize all public properties of the source object with data from a data row.
        /// </summary>
        /// <typeparam name="T">The Type</typeparam>
        /// <param name="source">The object to be auto initialized.</param>
        /// <param name="row">The data row containing the data for initializing.</param>
        /// <remarks>
        /// Uses the following default bindings: BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty;
        /// </remarks>
        public static void AutoInitialize<T>(this T source, DataRow row)
        {
            const BindingFlags flags =
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.SetProperty;
            source.AutoInitialize(row, flags);
        }
    
        /// <summary>
        /// Auto initialize all properties specified by the binding flags of the source object with data from a data row.
        /// </summary>
        /// <typeparam name="T">The Type</typeparam>
        /// <param name="source">The object to be auto initialized.</param>
        /// <param name="row">The data row containing the data for initializing.</param>
        /// <param name="flags">The binding flags used for property accessability. See <see cref="BindingFlags"/></param>
        /// <remarks>
        /// 
        /// </remarks>
        public static void AutoInitialize<T>(this T source, DataRow row, BindingFlags flags)
        {
            source.AutoInitialize(row, flags, true);
        }
    
        /// <summary>
        /// Auto initialize all properties specified by the binding flags of the source object with data from a data row.
        /// </summary>
        /// <typeparam name="T">The Type</typeparam>
        /// <param name="source">The object to be auto initialized.</param>
        /// <param name="row">The data row containing the data for initializing.</param>
        /// <param name="flags">The binding flags used for property accessability. See <see cref="BindingFlags"/></param>
        /// <param name="ignoreException">True to hide any ArgumentExceptions</param>
        /// <remarks>
        /// 
        /// </remarks>
        public static void AutoInitialize<T>(this T source, DataRow row, BindingFlags flags, bool ignoreException)
        {
            if (row == null) return;
    
            // Get all the public - instace properties that contains a setter.
            var properties = source.GetType().GetProperties(flags);
            foreach (var property in properties)
            {
                // Get the column name from the column or use the property name.
                var columnName = property.Name;
    
                // Get the property type.
                var propertyType = property.PropertyType;
    
                try
                {
                    // Retreive the row value given the column name.
                    var rowValue = row[columnName];
                    // Determin that the row value is not null (DBNull)
                    if (rowValue != Convert.DBNull)
                    {
                        // Get the converter for this property.
                        var converter = TypeDescriptor.GetConverter(propertyType);
                        if (converter != null)
                        {
                            // Convert the row value to the property type.
                            var data = converter.ConvertFrom(rowValue);
                            // If the converted type matches the property type, then set the data to the source.
                            if (data.GetType() == propertyType) property.SetValue(source, data, null);
                        }
                    }
                }
                catch (ArgumentException)
                {
                    // Exception during operations. Proerties without setters will cause an ArgumentException.
                    //   Since this extension will process all getters and setters that are public, any
                    //   object that has readonly or writeonly fields and/or properties will throw an Exception
                    if (!ignoreException) throw;
                }
                catch (Exception)
                {
                    // Exception during operation
                    // Most likely that the row does not contain the property name.
                    if (!ignoreException) throw;
                }
            }
        }
    
    
    // Custom object containing just the public properties
        /// <summary>
        /// Enum of the different header types available.
        /// </summary>
        public enum HeaderRaceType
        {
            Totals,
            Issues,
            Race
        }
    
        /// <summary>
        /// Encapislates information about the BOE header file and data file.
        /// </summary>
        public class Boe
        {
    
            public Boe( )
            {
                _cand = new Candidate( );
                //_office = new Office( );
            }
    
            #region Classes
    
            #region Nested type: Candidate
    
            internal class Candidate
            {
                private string _fName = String.Empty;
                private bool _isJr;
                private bool _isNumeric;
                private bool _isSr;
                private string _lName = String.Empty;
                private string _mName = String.Empty;
                private string _suffix = String.Empty;
    
                internal string FirstName
                {
                    get { return _fName; }
                    set { _fName = value; }
                }
    
                internal string MiddleName
                {
                    get { return _mName; }
                    set { _mName = value; }
                }
    
                internal string LastName
                {
                    get { return _lName; }
                    set { _lName = value; }
                }
    
                internal string Suffix
                {
                    get { return _suffix; }
                    set
                    {
                        if ( value == String.Empty ) return;
                        _isJr = false;
                        _isSr = false;
                        _isNumeric = false;
                        _suffix = value;
                        // ReSharper disable PossibleNullReferenceException
                        if ( _suffix.Contains( "jr" ) || _suffix.Contains( "Jr" ) || _suffix.Contains( "JR" ) )
                        { IsJr = true; _suffix = "Jr"; }
                        else if ( _suffix.Contains( "sr" ) || _suffix.Contains( "Sr" ) || _suffix.Contains( "SR" ) )
                        { IsSr = true; _suffix = "Sr"; }
                        else if ( _suffix.Contains( "II" ) || _suffix.Contains( "IV" ) || _suffix.Contains( "V" ) )
                        {
                            IsNumeric = true;
                            if ( _suffix.Contains( "IV" ) ) { _suffix = "IV"; }
                            else if ( _suffix.Contains( "VIII" ) ) { _suffix = "VIII"; }
                            else if ( _suffix.Contains( "VII" ) ) { _suffix = "VII"; }
                            else if ( _suffix.Contains( "VI" ) ) { _suffix = "VI"; }
                            else if ( _suffix.Contains( "V" ) ) { _suffix = "V"; }
                            else if ( _suffix.Contains( "III" ) ) { _suffix = "III"; }
                            else if ( _suffix.Contains( "II" ) ) { _suffix = "II"; }
                        }
                    }
                }
    
                internal bool IsJr
                {
                    get { return _isJr; }
                    set {
                        _isJr = value;
                        if ( !_isJr ) return;
                        _isSr = !_isJr;
                        _isNumeric = !_isJr;
                    }
                }
    
                internal bool IsSr
                {
                    get { return _isSr; }
                    set
                    {
                        _isSr = value;
                        if ( !_isSr ) return;
                        _isJr = !_isSr;
                        _isNumeric = !_isSr;
                    }
                }
    
                internal bool IsNumeric
                {
                    get { return _isNumeric; }
                    set
                    {
                        _isNumeric = value;
                        if ( !_isNumeric ) return;
                        _isJr = !_isNumeric;
                        _isSr = !_isNumeric;
                    }
                }
    
                internal string CandidateName
                {
                    get
                    {
                        var sb = new StringBuilder( LastName );
                        if ( FirstName != String.Empty )
                        {
                            sb.Append( ", " + FirstName );
                            if ( MiddleName != String.Empty )
                            {
                                sb.Append( " " + MiddleName );
                            }
                        }
                        return sb.ToString();
                    }
                }
    
                internal string FullName
                {
                    get
                    {
                        var sb = new StringBuilder( LastName );
                        if ( FirstName != String.Empty )
                        {
                            sb.Append( ", " + FirstName );
                            if ( MiddleName != String.Empty )
                            {
                                sb.Append( " " + MiddleName );
                            }
                        }
                        if ( Suffix != String.Empty )
                        {
                            sb.Append( " " + Suffix );
                        }
                        return sb.ToString();
                    }
                }
    
                internal void ResetCandidate()
                {
                    _isJr = false;
                    _isSr = false;
                    _isNumeric = false;
                    _suffix = String.Empty;
                    _fName = String.Empty;
                    _mName = String.Empty;
                    _lName = String.Empty;
                }
            }
    
            #endregion
    
            #region Nested type: Precinct
    
            /// <summary>
            /// Internal class to hold votes for each race by precinct
            /// </summary>
            public class Precinct
            {
                public bool PrecinctRaceTotal { get; set; }
                public string PrecinctCode { get; set; }
                public string PrecinctName { get; set; }
                public int PrecinctVotes { get; set; }
                public int CongressionalDistrict { get; set; }
                public int StateSenateDistrict { get; set; }
                public int StateHouseDistrict { get; set; }
                public int SplitSequence { get; set; }
            }
    
            #endregion
    
            #endregion
    
            #region Private field members
    
            /// <summary>
            /// List of precinct class objects
            /// </summary>
            private readonly List<Precinct> _precincts = new List<Precinct>();
    
            /// <summary>
            /// Internal clase that holds the candidate name with properties for isJr?, isSr?, isNumeric?, 
            /// FirstName (first name), MiddleName (middle name), LastName (last name), Suffix, 
            /// CandidateName (format: last, first middle), Full candidate name (format: first middle last suffix)
            /// and a method ResetCandidate to reset candidate object values.
            /// </summary>
            private Candidate _cand;
    
            /// <summary>
            /// Backing member variable of county code property
            /// </summary>
            private decimal _countyCode;
    
            /// <summary>
            /// Backing membar variable of county name property
            /// </summary>
            private string _countyName;
    
            private HeaderRaceType _headerRaceType;
    
            /// <summary>
            /// Backing member variable of party porperty
            /// </summary>
            private string _party;
    
            #endregion
    
            #region Class Properties
    
            #region Public AutoProperties
            public string FileHeaderName { get; set; }
            [ShredInclude]
            public decimal ElectionId { get; set; }
            [ShredInclude]
            public string ElectionGuid { get; set; }
            [ShredExclude]
            public string ElectionName { get; set; }
            [ShredExclude]
            public string ElectionDate { get; set; }
            /// <summary>
            /// Gets or sets the race GUID.
            /// </summary>
            /// <value>The race GUID.</value>
            public string RaceId { get; set; }
            [ShredExclude]
            public string RaceName { get; set; }
            /// <summary>
            /// Property which holds the code for the race in which the candidate is running.
            /// </summary>
            [ShredExclude]
            public string RaceCode { get; set; }
            [ShredExclude]
            public string RaceOfficeType { get; set; }
            [ShredExclude]
            public string RacePartyCode { get; set; }
            [ShredExclude]
            public string RacePartyName { get; set; }
            [ShredExclude]
            public string RaceCandidateId { get; set; }
            [ShredExclude]
            public string OfficeId { get; set; }
            [ShredExclude]
            public string OfficeName { get; set; }
            [ShredExclude]
            public string OfficeType { get; set; }
            [ShredExclude]
            public string CandidateIssueId { get; set; }
            [ShredExclude]
            public string ElectionRaceCandidateId { get; set; }
            [ShredExclude]
            public string ElectionCandDistEligId { get; set; }
            [ShredInclude]
            public decimal OutputOrder { get; set; }
            //[ShredExclude]
            //public RaceMap RaceMap { get; set; }
    
            /// <summary>
            /// Gets or sets the ordinal for the column header.
            /// </summary>
            /// <value>The ordinal.</value>
            [ShredInclude]
            public int Ordinal { get; set; }
    
            /// <summary>
            /// The sort order of the Header
            /// </summary>
            [ShredInclude]
            public decimal SortOrder { get; set; }
    
            /// <summary>
            /// Gets or sets the file header id.
            /// </summary>
            /// <value>The file header id.</value>
            [ShredInclude]
            public decimal FileHeaderId { get; set; }
    
            /// <summary>
            /// The race header used by SOS
            /// </summary>
            [ShredInclude]
            public string HeaderCaption { get; set; }
    
            /// <summary>
            /// The race header used by the county BOE
            /// </summary>
            [ShredInclude]
            public string BoeRaceHeader { get; set; }
    
            [ShredExclude]
            public List<string> Opponents { get; set; }
    
            ///// <summary>
            ///// The offical office name
            ///// </summary>
            ///// <remarks>If the BOE gave only a candidates last name and there are more than one  
            ///// candidate with that name, then there will be more than one office name.</remarks>
            //public string OfficeName { get; set; }
    
            ///// <summary>
            ///// Gets or sets the office GUID.
            ///// </summary>
            ///// <value>The office GUID.</value>
            ///// <remarks>If the BOE gave only a last name and there are more than one  
            ///// candidate with that name, then there will be more than one office id.</remarks>
            //public string OfficeGuid { get; set; }
    
            /// <summary>
            /// The offical race name used by the BOE
            /// </summary>
            [ShredExclude]
            public string Race { get; set; }
    
            /// <summary>
            /// Gets or sets a value indicating whether this <see cref="Boe"/> is exclude.
            /// </summary>
            /// <value><c>true</c> if exclude; otherwise, <c>false</c>.</value>
            [ShredExclude]
            public bool Exclude { get; set; }
    
            #endregion
    
            /// <summary>
            /// The type of header this class object.
            /// </summary>
            /// <remarks>The types are: HeaderRaceType.Totals, HeaderRaceType.Race, HeaderRaceType.Issues</remarks>
            [ShredExclude]
            public HeaderRaceType HeaderType
            {
                get { return _headerRaceType; }
                set
                {
                    if ( value == HeaderRaceType.Issues || value == HeaderRaceType.Totals ) { _cand = null; }
                    _headerRaceType = value;
                }
            }
    
            /// <summary>
            /// Property which holds the party of the candidate.
            /// </summary>
            /// <remarks>Only the capitalized first letter is retained.</remarks>
            [ShredInclude]
            public string Party
            {
                get { return _party; }
                set
                {
                    if ( value == String.Empty ) return;
    
                    _party = value.ToUpper().ElementAt( 0 ).ToString(CultureInfo.InvariantCulture);
    
                    if ( _cand == null ) _cand = new Candidate();
                }
            }
    
            /// <summary>
            /// The candidates last name
            /// </summary>
            [ShredInclude]
            public string LastName
            {
                get { return _cand != null ? _cand.LastName : String.Empty; }
                set { _cand.LastName = value; }
            }
    
            /// <summary>
            /// The candidates first name
            /// </summary>
            /// <remarks>In some cases the first name is not given by the boe and therefore will be blank.</remarks>
            [ShredInclude]
            public string FirstName
            {
                get { return _cand != null ? _cand.FirstName : String.Empty; }
                set { _cand.FirstName = value; }
            }
    
            /// <summary>
            /// The candidates middle name
            /// </summary>
            /// <remarks>In some cases the middle name is not given by the boe and therefore will be blank.</remarks>
            [ShredInclude]
            public string MiddleName
            {
                get { return _cand != null ? _cand.MiddleName : String.Empty; }
                set { _cand.MiddleName = value; }
            }
    
            /// <summary>
            /// The candidates name suffix
            /// </summary>
            /// <remarks>In some cases a name suffix is not given by the boe and therefore will be blank.</remarks>
            [ShredInclude]
            public string Suffix
            {
                get { return _cand != null ? _cand.Suffix : String.Empty; }
                set { _cand.Suffix = value; }
            }
    
            /// <summary>
            /// Property which holds the race candidates name. Format: Last, First
            /// </summary>
            /// <remarks>During the process of working with the parameter the following are removed: periods, both '(' and ')', '(WI)', 'jr' and 'sr'. If the name contains one of the following: '/', '\', '&amp;', it is considered to be the candidate with a running mate. The running mate is disguarded and the candidate name is processed as the other candidates.</remarks>
            [ShredInclude]
            public string CandidateName
            {
                get { return _cand != null ? _cand.CandidateName : String.Empty; }
                //set { // Shortened }
            }
    
            /// <summary>
            /// Gets the full name of the candidate. Use is places where middle name and suffix are desired.
            /// </summary>
            /// <value>The full name of the candidate.</value>
            [ShredExclude]
            public string CandidateFullName
            {
                get { return _cand != null ? _cand.FullName : String.Empty; }
            }
    
            /// <summary>
            /// Property which holds the county name for a county. 
            /// </summary>
            /// <remarks>The county name will have the first letter of each word capitalized and the rest will be lowercased.</remarks>
            [ShredInclude]
            public string CountyName
            {
                get { return _countyName; }
                set
                {
                    if ( value == String.Empty ) return;
                    _countyName = value.CapitalizeWords();
                }
            }
    
            /// <summary>
            /// Property which holds the county code for a county
            /// </summary>
            /// <remarks>Asserts that code is &gt;= 1 and &lt;= 88</remarks>
            [ShredInclude]
            public decimal CountyCode
            {
                get { return _countyCode; }
                set
                {
                    if ( value >= 1 && value <= 88 )
                    {
                        _countyCode = value;
                    }
                }
            }
    
            /// <summary>
            /// Gets the precinct count.
            /// </summary>
            /// <value>The precinct count.</value>
            [ShredExclude]
            public int PrecinctCount
            {
                get
                {
                    return _precincts.Count(p => p.SplitSequence == 1);
                }
            }
    
            /// <summary>
            /// Gets the precinct count with spilts.
            /// </summary>
            /// <value>The precinct count w/splits.</value>
            [ShredExclude]
            public int PrecinctCountWithSplits
            {
                get { return _precincts.Count(); }
            }
    
            /// <summary>
            /// Determine if the precinct has splits
            /// </summary>
            [ShredExclude]
            public bool PrecinctHasSplits
            {
                get { return PrecinctCount != PrecinctCountWithSplits; }
            }
    
            /// <summary>
            /// Gets the total votes. All precincts other than ZZZ.
            /// </summary>
            /// <value>The total votes.</value>
            [ShredInclude]
            public int TotalVotes
            {
                get { return _precincts.Where( p => !p.PrecinctRaceTotal ).Sum( p => p.PrecinctVotes ); }
            }
    
            /// <summary>
            /// Determine if the sum of the votes equal the precinct 'ZZZ' value.
            /// </summary>
            /// <returns>The sum of all the precicnts votes for this race.</returns>
            [ShredExclude]
            public bool DataIsValid
            {
                get { return TotalVotes == SummaryVotes; }
            }
    
            /// <summary>
            /// Gets the precincts.
            /// </summary>
            /// <value>The precincts.</value>
            [ShredExclude]
            public List<Precinct> Precincts
            {
                get { return _precincts; }
            }
    
            /// <summary>
            /// Gets or sets a value indicating whether this instance is sr.
            /// </summary>
            /// <value><c>true</c> if this instance is sr; otherwise, <c>false</c>.</value>
            [ShredExclude]
            public bool IsSr
            {
                get { return _cand != null && _cand.IsSr; }
                set { _cand.IsSr = value; }
            }
    
            /// <summary>
            /// Gets or sets a value indicating whether this instance is jr.
            /// </summary>
            /// <value><c>true</c> if this instance is jr; otherwise, <c>false</c>.</value>
            [ShredExclude]
            public bool IsJr
            {
                get { return _cand != null && _cand.IsJr; }
                set { _cand.IsJr = value; }
            }
    
            /// <summary>
            /// Gets or sets a value indicating whether this instance has numeric suffix.
            /// </summary>
            /// <value>
            /// 	<c>true</c> if this instance is numeric; otherwise, <c>false</c>.
            /// </value>
            [ShredExclude]
            public bool IsNumeric
            {
                get { return _cand != null && _cand.IsNumeric; }
                set { _cand.IsNumeric = value; }
            }
    
            #endregion
        }
    




    • Moved by Leo Liu - MSFT Tuesday, February 7, 2012 6:15 AM Moved for better support. (From:Visual C# Language)
    Monday, February 6, 2012 9:05 PM

All replies