I have a property of the "Form1" class called "InfoTest" that has some custom attributes that I want to access.
The code works fine, but is a bit unwieldy:
[Test("foo",15)]
public double InfoTest { get; set; }
public void RetrieveAttribute()
{
PropertyInfo field_info = typeof(Form1).GetProperty("InfoTest");
object[] custom_attributes = field_info.GetCustomAttributes(typeof(TestAttribute), false);
TestAttribute thisAttribute = (TestAttribute)custom_attributes[0];
Debug.WriteLine(thisAttribute.Info + "," + thisAttribute.TheValue);
}
I presume the answer is "No", but is there a simpler way of getting the attributes for InfoTest, that doesn't involve the `typeof(Form1).GetProperty("InfoTest")? I can't go (for example):
var runtimePropInfo = InfoTest.GetType().GetRuntimeProperties();
var propInfo = InfoTest.GetType().GetProperties();
...Which is essentially because it is trying to get the properties of a "double", not a "InfoTest" object.
Just relying on built-in functions, you can simplify it a bit by using an extension method on MemberInfo that can directly return a custom attribute.
PropertyInfo field_info = typeof(Form1).GetProperty("InfoTest");
TestAttribute thisAttribute = field_info.GetCustomAttribute<TestAttribute>(false);
Debug.WriteLine(thisAttribute.Info + "," + thisAttribute.TheValue);
That gets rid of an object array, and a type-cast.
If you are willing to use a custom extension method, you can use this one to simplify it to one function call. It has the benefit of being strongly typed, though it may not be as performant.
public static class ReflectionExtensions
{
public static TAttribute GetAttribute<TAttribute, TClass>(this TClass target, Expression<Func<TClass, object>> targetProperty) where TAttribute : Attribute
{
var lambda = (LambdaExpression) targetProperty;
var unaryExpression = (UnaryExpression) lambda.Body;
string name = ((MemberExpression) unaryExpression.Operand).Member.Name;
MemberInfo info = typeof(TClass).GetProperty(name);
return info.GetCustomAttribute<TAttribute>(false);
}
}
It can be used on anything (it's an extension of object) like this:
var attr = thing.GetAttribute<TestAttribute, Thing>(obj => obj.InfoTest);
It gets the TestAttribute from the InfoTest property of thing, which is an instance of the Thing class.
Thing is defined as:
public class Thing
{
[Test("foo", 15)]
public double InfoTest { get; set; }
}
Related
So, I was wondering if it possible to do the next thing in c#:
I have a DB model - let's say it is Car:
public class Car {
public string Id {get;set;}
public string Name {get;set}
}
And a DbSet for this type in someDbContext:
public DbSet<Car> Cars {get;set;}
And also I have a CarDto
public class CarDto {
public string Id {get;set;}
public string Name {get;set}
}
And as result we get something like this:
var select = new Func<CarDto, bool>(car => car.Name == "BMW");
// And somehow use this expression for other type Car
someDbContext.Cars.Where(select);
Maybe there is an approach in which I could map these Funcs like this:
var newFunc = mapper.Map<Func<Car, bool>>(select);
Any thoughts?
If you just want to handle rewriting property accesses, you can use an ExpressionVisitor which looks a bit like this:
public class Program
{
public static void Main()
{
Expression<Func<Car, bool>> expr = x => x.Name == "BMW";
var replaced = ReplaceParameter<CarDto>(expr);
}
private static Expression<Func<T, bool>> ReplaceParameter<T>(LambdaExpression expr)
{
if (expr.Parameters.Count != 1)
throw new ArgumentException("Expected 1 parameter", nameof(expr));
var newParameter = Expression.Parameter(typeof(T), expr.Parameters[0].Name);
var visitor = new ParameterReplaceVisitor()
{
Target = expr.Parameters[0],
Replacement = newParameter,
};
var rewrittenBody = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(rewrittenBody, newParameter);
}
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
public ParameterExpression Target { get; set; }
public ParameterExpression Replacement { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == this.Target)
{
// Try and find a property with the same name on the target type
var members = this.Replacement.Type.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Public | BindingFlags.Instance);
if (members.Length != 1)
{
throw new ArgumentException($"Unable to find a single member {node.Member.Name} of type {node.Member.MemberType} on {this.Target.Type}");
}
return Expression.MakeMemberAccess(this.Replacement, members[0]);
}
return base.VisitMember(node);
}
}
We need to deconstruct the LambdaExpression into its body and parameters. We need to create a new parameter which has the correct type, and replace all usages of the old parameter with the new one. This is where the visitor comes in: whenever it sees you access a member on the old parameter, it tries to find the corresponding member on the new parameter, and access that instead.
We then construct a new LambdaExpression, using the rewritten body and the new parameter.
You have a whole bunch of options:
Derive your Dto class from the context class. That way you can use polymorphism as normal.
Extract an interface and implement it in both your Dto and context classes. Same as above then, use polymorphism.
Use duck-typing. In C#, that's done with the dynamic keyword. You lose Intellisense and compile-time error checking, but your code will work.
Reflection. It's a lot of code, it's slow, it's practically a much worse version of #3, but you can cobble it together if you really try.
Something like Automapper will help you map your context to your Dto piece-wise, but it won't help you translate your lambda function filters.
I want to implement this method from MOQ. (Little out of my depth here)
ISetup<T> Setup(Expression<Action<T>> expression);
public class Foo {
public string Bar { get; set; }
public int Baz { get; set; }
}
public class MyCoolClass
{
public ? Evaluate<Expression<Action>>(expression);
//I want to be able to access and test the value of Foo.Bar (see below)
}
public class ClientOfMyClass
{
public void UseTheMethod()
{
MyCoolClass myCool = new MyCoolClass();
bool result = myCool.Evaluate<Foo>(f => f.Bar);
}
}
Basically, I am trying to write a method that will allow the caller to specify a property on an object with an expression, and allow me to test the value of that property and do something with it.
You want to use an Expression<Func<>> parameter, and check that it contains a Body, and a Member of type PropertyInfo, and use GetValue() passing your object in.
public static void Evaluate<TObj,TProp>(
this TObj obj,
Expression<Func<TObj, TProp>> expr)
{
var prop = (expr.Body as MemberExpression)?.Member as PropertyInfo;
var val = prop?.GetValue(obj);
if (val != null) {
//Do something
}
}
Note that the above code requires the passed in lambda to point to a Property. If you want to handle Fields as well as Methods, they will come in as different types of Expressions, and you'll want to handle handle them slightly differently. For more context and usage, here's a Fiddle.
Edit: Updated to work with other property types.
I want to execute linq method on iqueryable with an expression tree from function where I'm passing name of linq method and name of property. But my sample method works only with mapped properties. It throws an exception when I try to for example to find max of calculated property.
My classes:
public partial class Something
{
public int a { get; set; }
public int b { get; set; }
}
public partial class Something
{
public int calculated { get { return a * b; } }
}
Sample method:
public static object ExecuteLinqMethod(IQueryable<T> q, string Field, string Method)
{
var param = Expression.Parameter(typeof(T), "p");
Expression prop = Expression.Property(param, Field);
var exp = Expression.Lambda(prop, param);
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp);
return q.Provider.Execute(mce);
}
To be able to query on calculated properties, you have at least 2 options:
1) you store the calculated values in the db with the rows (or in a different table), and use them in your queries of course this requires datamodel change, and redundancy in data, but is the most performant way. But is not that exciting, so lets move on to
2) you need to be able to express the way you "calculate" the properties in a way that sql will understand, meaning the property needs to be replaced with a linq expression in the final query. I found in 2009 an amazing article from Eric Lippert on registering inline such properties, but I cannot find it anymore. As such here is a link to another, that has the same idea. Basically you define your calculation as an expression tree, and use the compiled version in your code.
To make it more convenient, you would attribute your property with a
[AttributeUsage(AttributeTargets.Property)]
class CalculatedByAttribute: Attribute
{
public string StaticMethodName {get; private set;}
public CalculatedByAttribute(string staticMethodName)
{
StaticMethodName = staticMethodName;
}
}
Like:
public partial class Something
{
[CalculatedBy("calculatedExpression")]
public int calculated { get { return calculatedExpression.Compile()(this); } }
public static Expression<Func<Something, int>> calculatedExpression = s => s.a * s.b;
}
(of course you can cache the compilation) :)
Then in your method, if the property has your attribute, you get the static property value, and use that in your queries. Something along:
public static object ExecuteLinqMethod<T>(IQueryable<T> q, string Field, string Method)
{
var propInfo = typeof(T).GetProperty(Field);
LambdaExpression exp;
var myAttr = propInfo.GetCustomAttributes(typeof(CalculatedByAttribute), true).OfType<CalculatedByAttribute>().FirstOrDefault();
if (myAttr != null)
exp = (LambdaExpression)typeof(T).GetField(myAttr.StaticMethodName, BindingFlags.Static | BindingFlags.Public).GetValue(null);
else
{
var param = Expression.Parameter(typeof(T), "p");
Expression prop = Expression.Property(param, Field);
exp = Expression.Lambda(prop, param);
}
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp);
return q.Provider.Execute(mce);
}
I have a class that helps me read data from an MS SQL database into a list of objects. For the most part it's pretty straightforward; I can assume the property name of the class matches the column name of the table and just assign it accordingly, but sometimes I need to be able to transform data.
I have created a custom attribute to put on my class properties:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TransformDataAttribute : Attribute
{
public Func<object, string, object> TransformThisData { get; set; }
}
Now, let's say I want to create the Func on the fly, like this:
[TransformData(TransformThisData = new Func<object, string, object>((v, p) => "My name is " + v.ToString()))]
public string Name { get; set; }
The error that I am seeing is 'TransformThisData' is not a valid named attribute argument because it is not a valid attribute parameter type.
What is the best way to accomplish Func as a property attribute?
Well, here's the best I have been able to come up with.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TransformDataAttribute : Attribute
{
public string TransformDataClass { get; set; }
// This method must contain these parameters: (object value, PropertyInfo pi)
public string TransformDataMethod { get; set; }
}
I put it on the class property, like so...
public class Tracker
{
[TransformData(TransformDataClass = "CompanyTracker.DataTransformation", TransformDataMethod = "FunkyData")]
public string FunkyData { get; set; }
}
I can have a single data transformation class with different methods of transformation:
public class DataTransformation
{
public object FunkyData(object value, PropertyInfo pi)
{
// if data is this, return that, blah, blah
return value;
}
}
A static utility method for interpreting the three parameters:
public static object CallThisMethod(string className, string methodName, object[] parms)
{
Type type = Type.GetType(className);
MethodInfo theMethod = type.GetMethod(methodName);
object classInstance = Activator.CreateInstance(type);
return theMethod.Invoke(classInstance, parms);
}
...and then in my ADO Helper code, when it comes to assigning values to properties:
TransformDataAttribute attr = Utility.GetPropertyAttribute<TransformDataAttribute>(pi);
if (attr != null)
{
object[] parms = new object[] { value, pi };
value = Utility.CallThisMethod(attr.TransformDataClass, attr.TransformDataMethod, parms);
}
pi.SetValue(t, value, null);
It works. I hate to depend on Reflection of embedded strings for classes and methods, and it just doesn't seem like good design, but sometimes you just have to get things done. If anyone has a more elegant way to do this I'd be glad to hear about it.
I have a customer class with a sub-class address
internal class Customer
{
public int id { get; set; }
public string name { get; set; }
[ObjectDefRelation(isSubClass = true)]
public Addressinformation Addressinformation { get; set; }
}
internal class Addressinformation
{
public string street { get; set; }
}
I have a Method to fill this object with data from a xml. Now I want to call this method recursive when its arrive the sub-class Addressinformation. How can I call my generic method with informations from PropertyInfo?
public static T ConvertXmlToClass<T>(XmlDocument xmlDocumentObjectDef, XmlNode xmlNode, ObjectDefRelationAttribute parentClass = null) where T : new()
{
ObjectDefRelationAttribute defRelationAttribute;
T xmlToClass = new T();
foreach (PropertyInfo field in xmlToClass.GetType().GetProperties())
{
foreach (Attribute attr in field.GetCustomAttributes(true))
{
defRelationAttribute = attr as ObjectDefRelationAttribute;
if (null != defRelationAttribute)
{
if (defRelationAttribute.isSubClass)
{
//
// here I need help to call the recursive method (XXX)
//
var subClass = Helper.ConvertXmlToClass<XXX>(xmlDocumentObjectDef, xmlNode, defRelationAttribute);
}
}
}
}
}
I used the best answer with some modification:
Type typeArguments = GetType(field.PropertyType.Namespace + "." + field.PropertyType.Name);
object value = typeof(Helper).GetMethod("ConvertXmlToClass").MakeGenericMethod(typeArguments).Invoke(null, new object[] {xmlDocumentObjectDef, xmlNode, defRelationAttribute});
It seems that you've got a function that converts Type names to Types, something like this:
Type GetType(string typeName)
{
return Type.GetType(typeName);
}
then you can call this method as:
object value = typeof(owningType).GetMethod("ConvertXmlToClass").MakeGenericMethod(GetType(typeName)).Invoke(xmlDocumentObjectDef, xmlNode, xmlToClass);
and Use PropertyInfo.SetValue() to set it on the property
If you want to stick with your current approach then you need to use reflection to built the generic method call from the field.PropertyType as described here: Reflection and generic types
However you could also consider changing your method to accept a Type as parameter instead of making a generic method (hint you can use Activator.CreateInstance(type) to instantiate an object).