Clodoaldo Neto
Clodoaldo Neto

Reputation: 125204

Property name as variable

I need to find the biggest size of each string column in a database as one of the informations to design another database. The only access I have to the source database is by a web service. I can just do it for each of the many columns to find the biggest size but I want it generic so I can use it later.

I wrote this very simplified version to make it simple to understand. Two of the last lines have invented syntax and it is where I need help.

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

namespace ConsoleApplication1
{
    public class myClass
    {
        private string s;
        public string S
        {
            get { return s; }
            set { s = value; }
        }
        private int i;
        public int I
        {
            get { return i; }
            set { i = value; }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Type myClassType = typeof(myClass);
            System.Reflection.PropertyInfo[] propertyInfo = myClassType.GetProperties();
            Dictionary<string, int> property = new Dictionary<string, int>();

            foreach (System.Reflection.PropertyInfo info in propertyInfo)
               if (info.PropertyType == typeof(System.String))
                    property.Add(info.Name, -1);

            myClass[] myPa = new myClass[2];
            myPa[0] = new myClass();
            myPa[0].S = "1";
            myPa[0].I = 0;
            myPa[1] = new myClass();
            myPa[1].S = "12";
            myPa[1].I = 1;

This is where I need help. I invented the c[pair.key]. How to have a reference to a property that I know the name of?

            foreach (myClass c in myPa)
                foreach (KeyValuePair<string, int> pair in property)
                    if (c[pair.Key].Length > pair.Value)
                        property[pair.Key] = c[pair.Key].Length;

            foreach (KeyValuePair<string, int> pair in property)
                Console.WriteLine("Property: {0}, Biggest Size: {1}", pair.Key, pair.Value);
        }
    }
}

Output shoud be:

Property: S Biggest Size: 2

Upvotes: 0

Views: 746

Answers (2)

Reddog
Reddog

Reputation: 15579

The following should suffice:

static void Main()
{
    // Demo data
    myClass[] myPa = new myClass[2];
    myPa[0] = new myClass();
    myPa[0].S = "1";
    myPa[0].I = 0;
    myPa[1] = new myClass();
    myPa[1].S = "12";
    myPa[1].I = 1;

    PrintMaxLengthsOfStringProperties(myPa);
}

public static void PrintMaxLengthsOfStringProperties<T>(IEnumerable<T> items)
{
    var t = typeof(T);
    t.GetProperties().Where(p => p.PropertyType == typeof(string)) // TODO: Add other filters
                        .SelectMany(p => items.Select(o => (string)p.GetValue(o, null)).Select(v => new { Property = p, Value = v }))
                        .GroupBy(u => u.Property)
                        .Select(gu => new { Property = gu.Key, MaxLength = gu.Max(u => u.Value != null ? u.Value.Length : 0) })
                        .ToList()
                        .ForEach(u2 => Console.WriteLine("Property: {0}, Biggest Size: {1}", u2.Property.Name, u2.MaxLength))
                        ;
}

Though you might add some extra filters on the "GetProperties" result set (such as taking out static ones, or indexing properties, etc.

It makes use of a couple of Linq extension functions, namely, "Where", "GroupBy", "SelectMany", "Select", and "Max" as well using anonymous types.

Upvotes: 2

Tigran
Tigran

Reputation: 62248

Not very sure if I understood right, but:

What if just use indexed property in your class this[propertyname] which inside will return a value of specified property like an object.

    public class myClass
    {
        ....
        ....
        public object this[string propertyname]
        {
            get { /*use reflection to return property value, so Object*/ }

        }
        ....
        ....
    }

Which means, I'm afraid, you can not just write c[pair.key].Length, as Object does not have Length property. You need to cast it to desired type (string in your case) and only after use Length property.

If it's not what you were asking for, please refrase your question.

Upvotes: 0

Related Questions