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
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 think I'm having boxing issues
foreach(var p in item.GetType().GetProperties().
Where(p => p.GetValue(original, null) is ValueType))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (!originalValue.Equals(modifiedValue))
kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
originalValue is never equal to modifiedValue, Im guessing it's because they are boxed inside Object. But how do I fix it?
It is not a boxing issue. Equals is a virtual method, which the boxed value types override just fine.
However, I am not sure what the issue is. Could it be that there aren’t actually any matching properties? Remember that GetProperties() without any parameters will only return public properties. If the properties you need are private, you need to add some BindingFlags:
GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
(I’m assuming here that you don’t want static properties.)
Are you also sure that it is actually properties that you are after and not fields? Remember that if you declare something as
public string Name;
then it’s a field, whereas
public string Name { get; set; }
is a property. If it’s actually fields you need, you need to use GetFields() instead of GetProperties() with the same binding flags.
Linq is a great tool, but I'm not sure why you're using it here. You're actually causing the set of properties to get iterated twice, which is very expensive. I'd write the code without Linq. Also, there's no need to get the value more than once, which is again very expensive. Give this code a try. It avoids the flaws I pointed out and was comparing correctly when I made and tested a dummy class with it:
foreach(PropertyInfo p in item.GetType().GetProperties())
{
if (p.PropertyType.BaseType == typeof(ValueType) || p.PropertyType == typeof(string))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (originalValue != modifiedValue) kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
}
Also, note that strings are not a ValueType although they do implement a value comparison.
From MSDN: Object.Equals :
The default implementation of Equals supports reference equality for
reference types, and bitwise equality for value types. Reference
equality means the object references that are compared refer to the
same object. Bitwise equality means the objects that are compared have
the same binary representation.
That means that in your case this 2 objects (if they are reference types) are never point to the same instance.
There is no an easy way to resolve this in so generic way as you would like to do.
But you can implement (just an example) an IComparable on those types you gonna to compare, and after in this iteration check if the type of the value rturned implements that interface, so cast and call it's implemented IComparable.CompareTo method.
You can check if the object implements specified interfacce, in this current case IComparable, you can do something like this:
originalValue .GetType().GetInterfaces().Any(x =>
x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IComparable))
Hope this helps.
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));