Let's say we have the following classes defined like this
class Test {
public string Name { get; set; }
public string Type { get; set; }
public string SomeOtherValue { get; set; }
public Address Address { get; set; }
}
class Address {
public string AddressText { get; set; }
public string PostalCode { get; set; }
}
Then I have a need inside a method to do something with one or more of the properties in this class, and I would like to define which in a compile safe way. So I want to call the method like this:
MyFunction<Test>(t => new {t.Name, t.Address.AddressText});
Then inside MyFunction I need to know that "Name" and "Address.AddressText" are the selected properties, but I'm not sure how to get a hold of that
public void MyFunction<T>(Func<T, ?> param){
...
}
So my problem is I can't set the ? as the TResult
of Func
in any good way. If I could set that properly I guess I could take typeOf(TResult).GetProperties()
, but I feel I'm missing a piece to get this to work.
Update
I see there is a confusion what I'm trying to do here. I'll give an example from the MongoDB driver that behaves the same way I would like mye code to do
So lets say that testcoll
is a collection of Test
objects. In that case this will work, and will only return me a list of an anonymous type that only has the Name property.
await testcoll.Find(t => t.Type == "sometype").Project(t => new {t.Name}).ToListAsync();
So the question is basically. Inside Project
, how can I identify that Name
is the properties I want to fetch from the DB, and return in the anonymous type in the result?
Okay, I solved this now. It might be that my explanation in the questions is the problem. I want to get compile time safety for the parameter, and not getting the actual value compile time. That would of course not work.
So I want to be able to write
MyFunction<Test>(t => new {t.Name, t.Address.AddressText});
Instead of
MyFunction<Test>(new {"Name", "Address.AddressText"});
So that I wont get any typos in the parameters sent in, and will make sure that any change to the Test object will give me error here compile time.
I solved it like this:
public void MyFunction<T>(Expression<Func<T, object>> lambda)
{
List<string> arguments;
if (lambda.Body is NewExpression)
{
var args = (lambda.Body as NewExpression).Arguments;
arguments = args.Select(a =>
{
var aText = a.ToString();
var dotIndex = aText.IndexOf(".");
var result = aText.Substring(dotIndex + 1);
return result;
}).ToList();
}
else
{
throw new ArgumentException();
}
}
<do whatever I need to do here with the arguments list>
}
So for the example above where the argument is t => new {t.Name, t.Address.AddressText}
that will be converted to a list with the strings "Name"
and "Address.AddressText"
inside the method.