Is there a way to supply a name to a function that then returns the value of either the field or property on a given object with that name? I tried to work around it with the null-coalesce operator, but apparently that doesn't like different types (which is also a bit weird to me because null is null). I could separate it it out into if nulls, but there has to be a better way to do this. Here is my function, and the two lines with Comparison objects don't compile, but I will leave them in there to show what I am trying to do.
private void SortByMemberName<T>(List<T> list, string memberName, bool ascending)
{
Type type = typeof (T);
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
if (info == null)
{
throw new Exception("Member name supplied is neither a field nor property of type " + type.FullName);
}
Comparison<T> asc = (t1, t2) => ((IComparable) info.GetValue(t1)).CompareTo(info.GetValue(t2));
Comparison<T> desc = (t1, t2) => ((IComparable) info.GetValue(t2)).CompareTo(info.GetValue(t1));
list.Sort(ascending ? asc : desc);
}
I have heard of something called dynamic LINQ that could be used, but for the sake of learning, I am doing it my way.
Change this line:
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
to this:
MemberInfo info = type.GetField(memberName) as MemberInfo ??
type.GetProperty(memberName) as MemberInfo;
because there's no implicit cast to the base class when using the ternary operator like that. The ternary requires that the types of all outputs be the same.
As of C# 9.0, this will finally be possible:
Target typed ?? and ?:
Sometimes conditional ?? and ?: expressions don’t have an obvious shared type between the branches. Such cases fail today, but C# 9.0 will allow them if there’s a target type that both branches convert to:
Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type
That means the code block in the question will also compile without errors; it will 'see' that FieldInfo and PropertyInfo have a shared base type, MemberInfo.
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
Related
In C#, given two input Types, it it possible to determine the output Type and implicit upcast Types for an operator? For example, consider the expression s + i. Say I have the following information:
short s;
int i;
Type leftType = typeof(short);
Type rightType = typeof(int);
Can I determine the following information about the expression s + i?
Type leftUpcastType = typeof(int);
Type rightUpcastType = typeof(int);
Type outputType = typeof(int);
I obviously could do this with an enormous lookup table of all the types and operators, but there might be an easier way. Ideally this would work for user-defined classes with operator overloads too, but that is a secondary requirement.
Yes, you can achieve this using the dynamic Type. Keep in mind, though, that dynamic will throw an exception for anything that can't be summed at runtime so you will need to ensure that you are only passing valid values or wrap in a try/catch.
var leftType = left.GetType();
var rightType = right.GetType();
var outputType = ((dynamic)left + (dynamic)right).GetType();
You can then infer from this information whether one, both or neither of the objects were converted for the operation.
The best way to do this is to examine the return type of an expression that adds two values of the types you're interested in. This way you don't need to worry about providing valid values for the addition at runtime, when all you care about is the return type.
You can either take an existing expression and walk down the expression tree if one is available to you, or do something like this:
static Type GetTypeOfSummation<T1, T2>()
{
var p1 = Expression.Parameter(typeof(T1), "t1");
var p2 = Expression.Parameter(typeof(T2), "t2");
LambdaExpression x = DynamicExpression.ParseLambda(new[] { p1, p2 }, null, "t1 + t2");
return x.Body.Type;
}
static void Main()
{
Console.WriteLine(GetTypeOfSummation<int, double>()); // System.Double
Console.WriteLine(GetTypeOfSummation<int, decimal>()); // System.Decimal
Console.WriteLine(GetTypeOfSummation<float, double>()); // System.Double
}
This generic method will return the type of the addition operation without actually performing the addition.
You can of course do this with Type instances instead of generic type parameters as well, if that's what you want:
static Type GetTypeOfSummation(Type t1, Type t2)
{
var p1 = Expression.Parameter(t1, "t1");
var p2 = Expression.Parameter(t2, "t2");
LambdaExpression x = DynamicExpression.ParseLambda(new[] { p1, p2 }, null, "t1 + t2");
return x.Body.Type;
}
To be clear, DynamicExpression is from the System.Linq.Dynamic namespace, which you can obtain by referencing: https://www.nuget.org/packages/System.Linq.Dynamic/
Is there a way to supply a name to a function that then returns the value of either the field or property on a given object with that name? I tried to work around it with the null-coalesce operator, but apparently that doesn't like different types (which is also a bit weird to me because null is null). I could separate it it out into if nulls, but there has to be a better way to do this. Here is my function, and the two lines with Comparison objects don't compile, but I will leave them in there to show what I am trying to do.
private void SortByMemberName<T>(List<T> list, string memberName, bool ascending)
{
Type type = typeof (T);
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
if (info == null)
{
throw new Exception("Member name supplied is neither a field nor property of type " + type.FullName);
}
Comparison<T> asc = (t1, t2) => ((IComparable) info.GetValue(t1)).CompareTo(info.GetValue(t2));
Comparison<T> desc = (t1, t2) => ((IComparable) info.GetValue(t2)).CompareTo(info.GetValue(t1));
list.Sort(ascending ? asc : desc);
}
I have heard of something called dynamic LINQ that could be used, but for the sake of learning, I am doing it my way.
Change this line:
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
to this:
MemberInfo info = type.GetField(memberName) as MemberInfo ??
type.GetProperty(memberName) as MemberInfo;
because there's no implicit cast to the base class when using the ternary operator like that. The ternary requires that the types of all outputs be the same.
As of C# 9.0, this will finally be possible:
Target typed ?? and ?:
Sometimes conditional ?? and ?: expressions don’t have an obvious shared type between the branches. Such cases fail today, but C# 9.0 will allow them if there’s a target type that both branches convert to:
Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type
That means the code block in the question will also compile without errors; it will 'see' that FieldInfo and PropertyInfo have a shared base type, MemberInfo.
MemberInfo info = type.GetField(memberName) ?? type.GetProperty(memberName);
I'm attempting to retrieve the value of a property from an instance of MemberExpression.
Here is what I have so far:
protected override void VisitMember(Context context, MemberExpression node)
{
var propertyInfo = node.Member as PropertyInfo;
if(propertyInfo != null)
{
var v = propertyInfo.GetValue(node.Member , null);
val = Convert.ToString(v);
}
context.State.Append(val);
}
Depending on the approach I take there are two problems: I don't know the expected type (string, int, etc...), and/or I have not been able access the instance from the MemberExpression.
I am writing a small lambda expressions to T-SQL converter. For example (u)=> u.FirstName == u.LastName; would convert to FirstName = 'chuck'. I've almost got it working!
update
I tried the following code:
...
var propertyInfo = node.Member as PropertyInfo;
if(propertyInfo != null)
{
var o = propertyInfo.GetValue(node.Expression, null);
}
...
It did not work. I get the following error:
System.Reflection.TargetException : Object does not match target type.
update 2
This is what I am trying to accomplish:
public static Func<T, object> GetValueGetter<T>(this PropertyInfo propertyInfo)
{
if (typeof(T) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<T, object>)Expression.Lambda(convert, instance).Compile();
}
But I do not know T at compile time.
I don't know the expected type (string, int, etc...),
Use Expression.Type
I have not been able access the instance from the MemberExpression
Use MemberExpression.Expression - obviously that's another expression, because you might have:
foo.GetBar(20).ToString().Length
in which case the Length property would be a MemberExpression, but the Expression property would give the MethodCallExpression for ToString.
I have not been able access the instance from the MemberExpression.
In your example u => u.FirstName == "chuck", there is no instance for which to fetch the FirstName property.
I think you actually want the name of the property - which is node.Member.Name (and is "FirstName" in your example). Note that this works for all MemberInfo, not just PropertyInfo, so fields will work as well. (You may want to test anyway, because Events are also member expressions, but don't make sense here.)
I don't know the expected type (string, int, etc...),
The expected type is either PropertyInfo.PropertyType or FieldInfo.FieldType.
I am working on a filtering function. The filter will be an expression tree build by an user. There will be about 30 fields the user can use for filtering. I think the best way is to create the object model with indexer and to access required values by index of enum type.
See this example:
enum Field
{
Name,
Date,
}
class ObjectModel
{
object this[Field Key]
{
get
{
//...
return xx;
}
}
}
I would like to ask how can I access an indexer from an expression tree.
I'll post a complete example on how to use an indexer:
ParameterExpression dictExpr = Expression.Parameter(typeof(Dictionary<string, int>));
ParameterExpression keyExpr = Expression.Parameter(typeof(string));
ParameterExpression valueExpr = Expression.Parameter(typeof(int));
// Simple and direct. Should normally be enough
// PropertyInfo indexer = dictExpr.Type.GetProperty("Item");
// Alternative, note that we could even look for the type of parameters, if there are indexer overloads.
PropertyInfo indexer = (from p in dictExpr.Type.GetDefaultMembers().OfType<PropertyInfo>()
// This check is probably useless. You can't overload on return value in C#.
where p.PropertyType == typeof(int)
let q = p.GetIndexParameters()
// Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type.
where q.Length == 1 && q[0].ParameterType == typeof(string)
select p).Single();
IndexExpression indexExpr = Expression.Property(dictExpr, indexer, keyExpr);
BinaryExpression assign = Expression.Assign(indexExpr, valueExpr);
var lambdaSetter = Expression.Lambda<Action<Dictionary<string, int>, string, int>>(assign, dictExpr, keyExpr, valueExpr);
var lambdaGetter = Expression.Lambda<Func<Dictionary<string, int>, string, int>>(indexExpr, dictExpr, keyExpr);
var setter = lambdaSetter.Compile();
var getter = lambdaGetter.Compile();
var dict = new Dictionary<string, int>();
setter(dict, "MyKey", 2);
var value = getter(dict, "MyKey");
To read from the indexer the IndexExpression contains directly the value of the indexed property. To write to it we must use Expression.Assign. Everything else is quite vanilla Expression. As written by Daniel the Indexer is normally called "Item". Note that Expression.Property has an overload that accepts directly the name of the indexer (so "Item"), but I chose to find it manually (so it can be reused). I have even put an example on how to use LINQ to find the exact overload of indexer you want.
Just as a curiosity, if you look on MSDN for example for Dictionary, under Properties you'll find Item
The indexer is a simple property, normally called Item. This means, you can access the indexer like any other property by using its name.
The name of the indexer property can be changed by the implementor of the class by means of the IndexerName attribute.
To reliably get the actual name of the indexer property, you have to reflect on the class and obtain the DefaultMember attribute.
More information can be found here.
I have a lambda expression which accepts, a int? (nullable integer),
which returns value if value exists or DBNull.Value otherwise.
Func<int?, object> getId = id => id.HasValue ? id.Value : (object)DBNull.Value;
The goal here is that, I want to make that expression slightly a bit more generic so that I can pass any nullable types like, DateTime?
So here is a non-functional code I was starting off with, but not sure where to specify nullable's type.
int? imageId;
DateTime? actionDate;
Func<Nullable<T>, object> getValue =
id => id.HasValue ? id.Value : (object) DBNull.Value;
SaveImage(getValue(imageId), getValue(actionDate));
Is it possible to specify generic type or should I create a named function to do so?
Since the purpose of the question is to use a lambda expression, here is a solution. It takes a different route by using weak typing instead of the proposed strong typing, but accomplishes the same thing nonetheless.
// A lambda solution
Func<object, object> fnGetValue =
v =>
ReferenceEquals(v, null)
? DBNull.Value
: v;
// Sample usage
int? one = 1;
int? two = null;
object o1 = fnGetValue(one); // gets 1
object o2 = fnGetValue(two); // gets DBNull
Edit: This loose typing works because the data type of the lambda argument v is of the struct itself and is not the Nullable type wrapper. Apparently the Nullable value that the caller uses has been resolved or 'unwrapped' by the time it hits the lambda argument and the lambda argument reveals a struct value or null; the Nullable wrapper is nowhere to be seen at this point (or as far as I can find). This behaviour can be proved by putting a debug breakpoint in the lambda at v and inspecting its value.
The good side effect of this behaviour is the lambda works equally well for both Nullable and non-Nullable types -- it's not restricted.
Instead of using generics, you can just make an extension method on Object to do the conversion.
Here's a sample program. The ToDbObject extension does the conversion:
using System;
static class Program
{
static object ToDbObject(this object value)
{
return value ?? DBNull.Value;
}
static void Main(string[] args)
{
int? imageId = 3;
DateTime? actionDate = null;
Console.WriteLine("ImageId {0}: [{1}] - {2}", imageId, imageId.ToDbObject(), imageId.ToDbObject().GetType());
Console.WriteLine("actionDate {0}: [{1}] - {2}", actionDate, actionDate.ToDbObject(), actionDate.ToDbObject().GetType());
Console.ReadKey();
}
}
The above prints:
ImageId 3: [3] - System.Int32
actionDate : [] - System.DBNull
It's correctly handling both cases.
I think you can do it by creating a delegate factory method where you can specify the generic type parameter:
public static Func<Nullable<T>, object> CreateGetValueFunc<T>() where T : struct
{
return id => id.HasValue ? id.Value : (object)DBNull.Value;
}
And you can use it in your example like this:
SaveImage(
CreateGetValueFunc<int>()(imageId),
CreateGetValueFunc<DateTime>()(actionDate));