Why does this work? - c#

I was googling trying to find a way to call Control.DataBindings.Add without using a string literal but getting the property name from the property itself, which I think would be less error prone, at least for my particular case, since I normally let Visual Studio do the renaming when renaming a property. So my code would look something like DataBindings.Add(GetName(myInstance.myObject)... instead of DataBindings.Add("myObject".... So I found this:
static string GetName<T>(T item) where T : class
{
var properties = typeof(T).GetProperties();
if (properties.Length != 1) throw new Exception("Length must be 1");
return properties[0].Name;
}
That would be called, assuming I have a property called One, this way: string name = GetName(new { this.One }); which would give me "One". I have no clue why does it work and whether is safe to use it or not. I don't even know what that new { this.One } means. And I don't know on which case could it happens that properties.Length is not 1.
By the way, I just tested to rename my property One to Two and Visual Studio turned new { this.One } into new { One = this.Two }, which when used with the GetName function gave me "One", which make the whole thing useless since the name I would be passing to Control.DataBindings.Add would be still "One" after renaming the property.

new { this.One } creates an instance of an anonymous type with one Property, which is, because you didn't specify a name, called "One". That's why it works.
if you use new { One = this.Two }, you give the property the name "One". If you would leave out the part "One = ", it would work again.
However, the method you are using might be misunderstood if one does not know how it's intended to be used and if one does not call it using an anonymous type.
There is another way if you don't want to use string literals, here is one of the examples you can find on the web:
http://www.codeproject.com/Tips/57234/Getting-Property-Name-using-LINQ.aspx

No, you do not have to stick to string literals:
public static class ControlBindingsCollectionExtensions
{
public static void Add<T>(this ControlBindingsCollection instance, Expression<Func<T, object>> property)
{
var body = property.Body as UnaryExpression;
var member = body.Operand as MemberExpression;
var name = member.Member.Name;
instance.Add(name);
}
}
Usage:
Control.DataBindings.Add<MyClass>(m => m.MyProperty);

Related

Call function in dynamic linq

I'm trying to call a function in a dynamic linq select statement, but im getting error:
No property or field 'A' exists in type 'Tuple2'
Example code:
void Main()
{
var a = new Tuple<int, int>(1,1);
var b = new[]{ a };
var q = b.AsQueryable().Select("A.Test(it.Item1)");
q.Dump();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
How should I change my code to get this working?
If I call built in function Convert.ToInt32 for example it works fine.
var q = b.AsQueryable().Select("Convert.ToInt32(it.Item1)");
Also how do I cast a property using dynamic linq?
var q = b.AsQueryable().Select("((float)it.Item1)");
I'll say that the dynamic-linq isn't "strong enough" to do these things. It looks for methods only in the given objects and some special classes: Math, Convert, the various base types (int, float, string, ...), Guid, Timespan, DateTime
The list of these types is clearly visible if you use ilspy/reflector on the file. They are in System.Linq.Dynamic.ExpressionParser.predefinedTypes .
Now, clearly I could be wrong, but this works: .Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()
showing that it's quite probable that that is the "correct" list.
There is an article here on how to modify Dynamic LINQ if you are interested http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html
Now, an intelligent man would take the source of dynamic linq and simply expand that array... But here there aren't intelligent men... There are only programmers that want blood! Blood but especially innards!
var type = typeof(DynamicQueryable).Assembly.GetType("System.Linq.Dynamic.ExpressionParser");
FieldInfo field = type.GetField("predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic);
Type[] predefinedTypes = (Type[])field.GetValue(null);
Array.Resize(ref predefinedTypes, predefinedTypes.Length + 1);
predefinedTypes[predefinedTypes.Length - 1] = typeof(A); // Your type
field.SetValue(null, predefinedTypes);
Do this (with the types you want) BEFORE the first call to Dynamic Linq (because after the first call the methods/properties of these types are cached)
Explanation: we use reflection to add our object(s) to this "special list".
I know there is already an accepted answer on this but it did not work for me. I am using Dynamic Linq 1.1.4. I wanted to do a query like this
$.GetNewestRisk() == null
Where GetNewestRisk() is a public method on the object represented by $. I kept getting this error "Error running query, Methods on type 'Patient' are not accessible (at index 2)".
I found in the source code there is a GlobalConfig object that allows a custom provider to be assigned which will hold all of the types you may want to work with. Here is the source code for the custom provider:
public class CustomTypeProvider: IDynamicLinkCustomTypeProvider
{
public HashSet<Type> GetCustomTypes()
{
HashSet<Type> types = new HashSet<Type>();
types.Add(typeof(Patient));
types.Add(typeof(RiskFactorResult));
types.Add(typeof(PatientLabResult));
types.Add(typeof(PatientVital));
return types;
}
}
Here is how I am using it:
System.Linq.Dynamic.GlobalConfig.CustomTypeProvider = new CustomType();
After making this call I am able to call methods on the objects inside of the expression.
#xanatos answer doesn't work for .Net Core version. So I've found something similar related by #Kent on the System.Dynamic.Linq.Core tests DynamicExpressionParserTests written by the library's author himself.
The given TestCustomTypeProviderClass allows you to use the DynamicLinqType class annotation which is pretty usefull for this problem.
To answer to question, you then just needed to defined the class (ensure to annotate with DynamicLinqType) :
[DynamicLinqType]
public static class A
{
public static int Test(int i)
{
return i++;
}
}
Add a customTypeProvider as mentioned above :
private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
private HashSet<Type> _customTypes;
public virtual HashSet<Type> GetCustomTypes()
{
if (_customTypes != null)
{
return _customTypes;
}
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly }));
return _customTypes;
}
}
and use a ParsingConfig with the configurable Select to call it :
var config = new ParsingConfig
{
CustomTypeProvider = new TestCustomTypeProvider()
};
var q = b.AsQueryable().Select(config, "A.Test(it.Item1)");
#Armand has put together a brilliant solution for this issue, and being the only solution I was able to find regarding this I want to add to it for anyone who tries the same approach.
The class that is marked with...
[DynamicLinqType]
... must be taken into consideration when you run the following line:
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })
In the solution provided above, this assumes the class that contains the function to be evaluated is on the same class the code currently resides in. If the methods are to be used outside of said class, the assembly will need to change.
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { typeof(AnotherClassName).Assembly })
Nothing changes from the solution above, this is just for clarification for anyone attempting to use it.
As regards the current version (1.2.19) of Dynamic LINQ, you will probably get another exception:
System.Linq.Dynamic.Core.Exceptions.ParseException : Enum value 'Test' is not defined in enum type 'A'
To make DLINQ know your type 'A', you have two options:
Set up parsing config with your own custom types provider where you directly specify the type 'A'.
Mark your type with the attribute [DynamicLinqType]. If that type is loaded into the current domain (that's the usual case), you don't have to do anything more since the default custom type provider already scans the current AppDomain for types marked with [DynamicLinqType]. And only if that's not the case, i.e. your type is not loaded into the current domain, you have to do something like in that answer.
What if you would like to use both approaches - the first for type 'A' and the second for type 'B'? In that case, you just have to "merge" your type 'A' with the default provider types:
public class DynamicLinqTests
{
[Test]
public void Test()
{
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var parsingConfig = new ParsingConfig
{
ResolveTypesBySimpleName = true,
CustomTypeProvider = new TestCustomTypesProvider()
};
var queryWithA = b.AsQueryable().Select(parsingConfig, "A.Test(it.Item1)");
queryWithA.ToDynamicList();
var queryWithB = b.AsQueryable().Select(parsingConfig, "B.Test(it.Item1)");
queryWithB.ToDynamicList();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
[DynamicLinqType]
public static class B
{
public static int Test(int i)
{
return i++;
}
}
public class TestCustomTypesProvider : DefaultDynamicLinqCustomTypeProvider
{
public override HashSet<Type> GetCustomTypes()
{
var customTypes = base.GetCustomTypes();
customTypes.Add(typeof(A));
return customTypes;
}
}
}
I may be confused but your syntax whereby you are using a string in your Selects doesn't compile for me. The following syntax works:
var q = b.AsQueryable().Select(it => A.Test(it.Item1));
var b = new[]{ a };
The above array is don't know what type of array , and it's not type safe ?
Your values are assigned in variant data type so it's not integer value (I think string value) ,when you get this values in your query must need to convert.toint32() because your class parameter data type is integer
Please try it
var b = new **int**[]{ a };
instead of var b = new[]{ a };
The important hint is here (in bold):
No property or field 'xxx' exists in **type** 'xxx'
And Please look this for previous discussion :
Dynamic Linq - no property or field exists in type 'datarow'
The following works for me:
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var q = b.AsQueryable().Select(it=>A.Test(it.Item1));
var q1 = b.AsQueryable().Select(it => Convert.ToInt32(it.Item1));
var q2 = b.AsQueryable().Select(it => (float) it.Item1);

Expression.Bind() - what does it actually do?

So I've been playing with dynamically building expression trees lately and came across this method, which seems kinda odd. At first I thought "oh cool this is exactly what I need" after constantly writing code along the lines of
var left = member is FieldInfo ? Expression.Field(instance, (FieldInfo)member) : Expression.Property(instance, (PropertyInfo)member);
var right = ...
var assign = Expression.Assign(left, right);
Yes, I know there is Expression.PropertyOrField() call, but it does roundtrip back to reflection to find member by name, where as I typically already have MemberInfo instance.
So anyway, I thought Expression.Bind() would be useful to me, but it does something I don't really understand. Given the following code:
void Main()
{
var m = typeof(Foo).GetField("Bar");
Expression.Bind(m, Expression.Constant("")).Dump();
}
public class Foo
{
public string Bar;
}
it produces MemberAssignment expression Bar = "". But there is no instance and no static reference. How would I ever apply this expression to and instance of Foo? I can't find any example of this method being used.
Object-Initializer expressions.
Let's say you had:
public class Foo
{
public int Property { get; set; }
}
Then you could do:
var parameter = Expression.Parameter(typeof(int), "i");
var newExpr = Expression.New(typeof(Foo));
var bindExprs = new[]
{
Expression.Bind(typeof(Foo).GetProperty("Property"), parameter)
// You can bind more properties here if you like.
};
var body = Expression.MemberInit(newExpr, bindExprs);
var lambda = Expression.Lambda<Func<int, Foo>>(body, parameter);
which is something like:
i => new Foo { Property = i }
Old:
I can't help you solve the "performance issue" you are determined to solve (will using Expression.PropertyOrField really introduce a bottleneck in your application? I'm somewhat skeptical. You should determine this before optimizing prematurely) (EDIT: Apologies for incorrectly assuming that this was a perf optimization, and as you've found out yourself, Expression.MakeMemberAccess is what you need), but I can tell you what Expression.Bind is useful for.

How to replace the string value in extension method for lambda

I would like to replace "PKMvrMedsProductIssuesId" for something like x=>x.PKMvrMedsProductIssueId or anything that is not based on a string. Why? Because if the database people choose to rename the field my program would crash.
public static SelectList MvrMedsProductErrors(this SelectList Object)
{
MedicalVarianceEntities LinqEntitiesCtx = new MedicalVarianceEntities();
var ProductErrorsListBoxRaw =
(
from x in LinqEntitiesCtx.ViewLookUpProductIssuesErrorsNames
select x
);
Object = new SelectList(ProductErrorsListBoxRaw, "PKMvrMedsProductIssuesId", "MvrMedsProductIssuesErrorsNames");
return Object;
}
You're using a SelectList. In order to call that constructor, you must have a string. Any change we could propose will still result in a string (from somewhere) being passed into that constructor.
The good news is: that string can come from anywhere. It can come from config, from the database... where ever you like.
I don't know the exact context here (what exactly "PKMvrMedsProductIssuesId" is) , but you can for example use such helper method:
public static string GetPropertyAsString<T>(Expression<Func<T, object>> expression)
{
return GetPropertyInfo(expression).Name;
}
To use an expression to get string:
GetPropertyAsString<MyType>(x => x.MyTypeProperty);
('MyTypeProperty' is your 'PKMvrMedsProductIssuesId' any 'MyType' one of your types where you may have your property defined)

Get the name of the first argument in an extension method?

string thing = "etc";
thing = thing.GetName();
//now thing == "thing"
Is this even possible?
public static string GetName(this object obj)
{
return ... POOF! //should == "thing"
}
I agree #Reed's answer. However, if you REALLY want to achieve this functionality, you could make this work:
string thing = "etc";
thing = new{thing}.GetName();
The GetName extension method would simply use reflection to grab the name of the first property from the anonymous object.
The only other way would be to use a Lambda Expression, but the code would definitely be much more complicated.
No. At the point you're using it, the "name" would be "obj" - This could be retrieved (with debugging symbols in place) via MethodBase.GetCurrentMethod().GetParameters()[0].Name.
However, you can't retrieve the variable name from the calling method.
If you need the original variable name inside an extension method, I think it's best to do this:
thing.DoSomething(nameof(thing));
public static string DoSomething(this object obj, string name) {
// name == "thing"
}
New in C# 6 is nameof() which would replace the extension method entirely.
if (x == null) throw new ArgumentNullException(nameof(x));
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode”
Somewhat related is the CallerMemberAttribute which will get the name of the method where the function was called. A useful comparison of the two methods, with examples relating to PropertyChanged events, also talks about the IL code generated (TL;DR: they're the same).

Specifying properties when initialising

void Foo()
{
string ID = "test";
var testctrl = new Control() {ID = (ID**!=null?ID**:ID)};
}
Is it possible to get the value of ID** in the code above? The problem is they both have the same property names.
Please ignore the fact the specific ID assignment is pointless, im just using it as an example.
Putting aside that the code can't possibly compile...
The first ID (ID=) in this syntax refers to the assignment, specifically the member being assigned. On the right-hand-side, it comes down to standard resolution. Which never means the ID of the new object. It will first look at the local ID variable, then after that members (fields etc) on the current instance. To prefer members on the current instance, use this.ID.
You might also want to consider the null-coalescing operator, so if you mean "the local-variable, or the instance-member if it is null, that would be ID ?? this.ID - but an even better idea would be to make unambiguous variable names ;-p
First remark about this line, it looks strange (assigning string to bool):
bool ID = "test";
Second remark, this works fine:
string ID = "test";
var testctrl = new Control(){ ID = (ID==null?ID:ID) };
Third remark: it is a convention in C# to name your local variables start with lowercase letter.
If you want to check if the new controls id is null then you should do this.
void Foo()
{
string ID = "test";
var testctrl = new Control();
if(testctrl.ID==null)
testctrl.ID = ID;
}
The question is not that clear to me, but do you want this:
void Foo()
{
bool ID = "test";
var testctrl = new Control(){ID = (this.ID==null?ID:this.ID)};
}
note, untested.
Seeing your example, I suspect that you don't have the requirement that the ID should be unique?
In general, to avoid nasty problems like this, avoid try using duplicate property names, but maybe your bound to an existing interface.
How about adding an constructor overload which takes the 'outer' ID as a parameter?
void Foo()
{
string ID = "test";
var testctrl = new Control(ID);
}
I think in general, if the property does more than just assignment (argument checking in this case), you should do it in the 'set' of the property itself and not during 'object initialization'.

Categories