Frazer
Frazer

Reputation: 606

Reference an c# Object Field by its name passed as a string

I am writing a custom repoting module using ASP.NET MVC in C#

The user will be able to define a list of the fields they want to see in the report.

I would like to know if it is possible to reference a object field using a string, so that I can enumerate through the list of chosen fields.

for example normally in the view, quite basically I would do the following

@foreach (Title item in Model)
{
    @item.Name 
    @item.Isbn
}

I would be looking for something like

@foreach (Title item in Model)
{
    @item.Select("Name")
    @item.Select("Isbn")
}

Upvotes: 4

Views: 4633

Answers (3)

René Vogt
René Vogt

Reputation: 43936

I'm not experienced with asp, so I don't know for sure if this is possible in your specific context.

But normally you could use reflection for that. But you had to know if you are looking for properties or fields

For fields:

FieldInfo fi = item.GetType().GetField("Name", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var value = fi.GetValue(item); // read a field
fi.SetValue(item, value); // set a field

For properties:

PropertyInfo pi = item.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var value = pi.GetValue(item); // read a property
pi.SetValue(item, value); // set a property

The word to google for is "Reflection" and most methods can be found in the Type class.

Upvotes: 0

Fabjan
Fabjan

Reputation: 13676

Well, i'd strongly recommend against using reflection in View as it breaks main principles of MVC pattern. YES, you should use reflection, but it is better to use it in controller. Let's have a look at simple and working example.

In controller we set up stub data to work with. And in action method About() we obtain a dynamic list of properties that user has selected :

class Title
{
    // ctor that generates stub data 
    public Title()
    {
        Func<string> f = () => new string(Guid.NewGuid().ToString().Take(5).ToArray());
        A = "A : " + f();
        B = "B : " + f();
        C = "C : " + f();
        D = "D : " + f();
    }

    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult About()
    {
        var data = new List<Title>()
        {
            new Title(), new Title(),
            new Title(), new Title()
        };

        // list of properties to display for user
        var fieldsSelectedByUser = new[] { "A", "C" };

        // here we obtain a list of propertyinfos from Title class, that user requested
        var propsInfo = typeof(Title).GetProperties().Where(p => fieldsSelectedByUser.Any(z => z == p.Name)).ToList();

        // query that returns list of properties in List<List<object>> format
        var result = data.Select(t => propsInfo.Select(pi => pi.GetValue(t, null)).ToList()).ToList();

        return View(result);
    }

    ...
}

And in view we can use it by simply iterating the collection :

@model List<List<object>>

<br/><br />

@foreach (var list in @Model)
{
    foreach (var property in list)
    {
        <p> @property&nbsp;&nbsp;</p>
    }

    <br/><br />
}

P.S.

According to MVC pattern, view should utilize data returned by controller but should at no circumstances perform any business logic and comprehensive operations inside of it. If view need some data in some format - it should get this data returned by controller exactly in the format it needs.

Upvotes: 0

Zein Makki
Zein Makki

Reputation: 30052

One of the ways to do that is through reflection. Add this helper method somewhere:

private object GetValueByPropertyName<T>(T obj, string propertyName)
{
    PropertyInfo propInfo = typeof(T).GetProperty(propertyName);

    return propInfo.GetValue(obj);
}

Usage:

@foreach (Title item in Model)
{
    var name =  GetValueByPropertyName(item, "Name");
    var isbn =  GetValueByPropertyName(item, "Isbn");
}

Upvotes: 1

Related Questions