PropertyInfo.SetValue ArgumentException? - c#

I have the following code. However, it has a runtime exception on SetValue. What may cause the error?
var _filter = new Filter(....); // Filter implemented IFilter
ApplyFilter(_view.Name, x => x.Name);
private void ApplyFilter<T>(T curr, Expression<Func<IFilter, T>> prev)
{
var expr = (MemberExpression)prev.Body;
var prop = (PropertyInfo)expr.Member;
if (!EqualityComparer<T>.Default.Equals(curr, (T)_filter[prop.Name]))
{
prop.SetValue(_filter, curr, null); // Error
..... // do something on _filter
The exception is:
System.ArgumentException was unhandled
Message=Property set method not found.
Source=mscorlib
StackTrace:
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
at MyApp.ErrorLogPresenter.ApplyFilter[T](T curr, Expression`1 prev) in d:\....cs:line 50

Message=Property set method not found.
This usually simply means that the property you are using does not define a setter. Either ensure that a suitable setter exists, or use a different approach to assign values.

Related

Reflection GetMethod with a type paramenter

The following line is not running properly, and I'm not sure why. The Error:
System.Reflection.TargetParameterCountException: parameters do not match signature
And the line of code in question:
typeof(Resources).GetMethod("LoadAll", new Type[] { typeof(System.String), typeof(System.Type)});
Displaying all functions of the Resources class shows:
UnityEngine.Object[] FindObjectsOfTypeAll(System.Type)
T[] FindObjectsOfTypeAll[T]()
UnityEngine.Object Load(System.String)
T Load[T](System.String)
UnityEngine.Object Load(System.String, System.Type)
UnityEngine.ResourceRequest LoadAsync(System.String)
UnityEngine.ResourceRequest LoadAsync[T](System.String)
UnityEngine.ResourceRequest LoadAsync(System.String, System.Type)
UnityEngine.Object[] LoadAll(System.String, System.Type)
UnityEngine.Object[] LoadAll(System.String)
T[] LoadAll[T](System.String)
UnityEngine.Object GetBuiltinResource(System.Type, System.String)
T GetBuiltinResource[T](System.String)
Void UnloadAsset(UnityEngine.Object)
UnityEngine.AsyncOperation UnloadUnusedAssets()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
System.String ToString()
System.Reflection.MethodInfo[]
I'm trying to match UnityEngine.Object[] LoadAll(System.String, System.Type). Any thoughts on what may be the issue?
Bonus if you can make a line that returns a methodinfo object for "T[] LoadAllT", specific to a given type.
The issue is that you are trying to get an instance level method while the LoadAll is static.
Try this one:
typeof(Resources).GetMethod("LoadAll",
System.Reflection.BindingFlags.Static,
new Type[] { typeof(System.String),typeof(System.Type)},
null);

Exception when I use Count method in Queryable class

In WinRT when I call the count method in Queryable class for the IOrderedEnumerable instance it will throw the exception.
DoWork(emp); //Working fine
DoWork(emp.OrderBy(objects => objects.EmployeeId)); //throw exception..
public void DoWork(IEnumerable<object> collection)
{
var queryable = collection.AsQueryable();
int count = 0;
if (queryable != null)
count = queryable.Count();
else
throw new InvalidOperationException("Not able to get count");
//Some other operations using queryable...
}
Exception
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The API 'System.Linq.OrderedEnumerable`2[[SfDataGrid.BusinessObjects, SfDataGrid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' cannot be used on the current platform. See http://go.microsoft.com/fwlink/?LinkId=248273 for more information.
Source=mscorlib
StackTrace:
at System.Reflection.Emit.DynamicILGenerator.GetTokenFor(RuntimeType rtType)
at System.Reflection.Emit.DynamicILGenerator.Emit(OpCode opcode, Type type)
at System.Linq.Expressions.Compiler.BoundConstants.EmitConstantFromArray(LambdaCompiler lc, Object value, Type type)
at System.Linq.Expressions.Compiler.BoundConstants.EmitConstant(LambdaCompiler lc, Object value, Type type)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitConstant(Object value, Type type)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitConstantExpression(Expression expr)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitArguments(MethodBase method, IArgumentProvider args, Int32 skipParameters)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type objectType, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCallExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody(CompilerScope parent, Boolean inlined, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody()
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
at System.Linq.EnumerableExecutor`1.Execute()
at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
at SfDataGrid.ViewModel.GetCount(IEnumerable`1 collection) in e:\DiskD\Support\I108101\SfDataGrid1022101733\SfDataGrid\SfDataGrid\ViewModel\ViewModel.cs:line 39
at SfDataGrid.ViewModel..ctor() in e:\DiskD\Support\I108101\SfDataGrid1022101733\SfDataGrid\SfDataGrid\ViewModel\ViewModel.cs:line 27
at SfDataGrid.SfDataGrid_XamlTypeInfo.XamlTypeInfoProvider.Activate_0_ViewModel() in e:\DiskD\Support\I108101\SfDataGrid1022101733\SfDataGrid\SfDataGrid\obj\Debug\XamlTypeInfo.g.cs:line 123
at SfDataGrid.SfDataGrid_XamlTypeInfo.XamlUserType.ActivateInstance() in e:\DiskD\Support\I108101\SfDataGrid1022101733\SfDataGrid\SfDataGrid\obj\Debug\XamlTypeInfo.g.cs:line 3679
It seems that IOrderedEnumerable<T>.AsQueryable() is implemented using dynamic code generation which is not available in WinRT. You could work around that by materializing it in a list before calling AsQueryable():
public void DoWork(IEnumerable<object> collection)
{
var queryable = collection.ToList().AsQueryable();
int count = 0;
if (queryable != null)
count = queryable.Count();
else
throw new InvalidOperationException("Not able to get count");
//Some other operations using queryable...
}
Unless you're working with very large collections performance shouldn't be much worse.
You must use IOrderable<object> instead of IEnumerable<object> as param for DoWork Method
IOrderable:
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.utilities.iorderable.aspx
IEnumerable:
http://msdn.microsoft.com/en-us/library/system.collections.ienumerable(v=vs.100).aspx

C# Reflection SetValue() can not find set accessor

I use reflection to update objects which have had updates made to them and saved to mongodb
private void updateSelf(MongoDoc newDoc)
{
Type type = this.GetType();
foreach (var i in type.GetProperties())
{
if (i.GetCustomAttributes(false).Any(x => x is MongoDB.Bson.Serialization.Attributes.BsonIgnoreAttribute)) continue;
Object oldValue = i.GetValue(this, null);
Object newValue = i.GetValue(newDoc, null);
if (!Object.Equals(oldValue, newValue) && !((oldValue == null) && (newValue == null)))
{
i.SetValue(this, newValue, null);
}
}
}
this is working for the most part but the i.SetValue(this, newValue, null); throws an exception when trying to update this property:
public uint Revision { get; private set; }
this is trying to update an object of type Product which is a derived type of MongoDoc which contains the property public uint Revision { get; private set; } which is causing the exception Property set Method not found I'm not sure what is causing this because it works on all my other properties, just this one throws and exception. Any help much appreciated
UPDATE:
I have tried the answer below:
i.SetValue(this, newValue, System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, null, null);
but unfortunately the exact same result, it still throws the exception on the Revision property.
UPDATE:
Exception:
System.ArgumentException was unhandled
Message=Property set method not found.
Source=mscorlib
StackTrace:
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
at Flo.Client.Docs.MongoDoc.updateSelf(MongoDoc newDoc) in F:\Flo\Flo.Client\Docs\MongoDoc.cs:line 162
at Flo.Client.Docs.MongoDoc.UpdateToMongo(MongoDoc newDoc) in F:\Flo\Flo.Client\Docs\MongoDoc.cs:line 120
at Flo.Client.Docs.Product.EditProduct(String Name, Nullable`1 State) in F:\Flo\Flo.Client\Docs\Product.cs:line 89
at Flo.Client.Program.Main() in F:\Flo\Flo.Client\Program.cs:line 26
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
I fixed it with this, thanks to Dylan Meador for pointing me to another question which gave me enough to get the solution:
private void updateSelf(MongoDoc newDoc, Type type)
{
foreach (var i in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
{
if (i.GetCustomAttributes(false).Any(x => x is MongoDB.Bson.Serialization.Attributes.BsonIgnoreAttribute)) continue;
Object oldValue = i.GetValue(this, null);
Object newValue = i.GetValue(newDoc, null);
if (!Object.Equals(oldValue, newValue) && !((oldValue == null) && (newValue == null)))
{
i.SetValue(this, newValue, null);
}
}
Type baseType = type.BaseType;
if (baseType != null)
{
this.updateSelf(newDoc, baseType);
}
}
It looks like the Type needed to be explicitly set to the base class type in order to use the set accessor for that particular property.
Try using the overload of SetValue that has an System.Reflection.BindingFlags parameter and pass it a value of BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic.
The problem is that from the point of view of the derived type there is no setter for the property.
You can work around this walking the inheritance hierarchy and getting the properties declared on each type (using the DeclaredOnly BindingFlag, together with Public and Instance), or checking whether the property is declared by the reflection type and if not get it again from the property info's DeclaringType.
For the former you'd you could have a nested loop, while the latter would look something like this:
foreach (var property in p.GetType().GetProperties())
{
var actualProperty = property.DeclaringType != property.ReflectedType ? property.DeclaringType.GetProperty(property.Name) : property;
actualProperty.SetValue(p, newValue, null);
}
Probably the issue can be in next:
You are using auto property
public uint Revision { get; private set; }
Which perform boxing/unboxing operations through default type int.
So, here you should explicitly cast to uint type.
You can find out similar problem with next snippet:
byte b1 = 4;
byte b2 = 5;
byte sum = b1 + b2;
This will raise an exception since no overload are declared for "+" operator.
This snippet actually demonstrate an issue with boxing/unboxing operations through default type int.

Is there any way to look up an item in the L2S identity map?

LINQ-2-SQL maintains an identity map so subsequent calls to entity.First(e => e.Id == id) do not cause additional queries beyond the first one for a context.
Is there anyway to ask L2S if a particular item exists in the identity map?
I ask this cause there is support for .Attach which allows you to attach entities to a context, however the method will exception out if the item already exists in the identity map.
In an interoperability scenario I may want to load up entities in a different, faster orm and attach, however it makes no sense to lookup an entity if it is already in the identity map.
No nice way... you can hack your way in, though. For example imagine you have a User object that you know is keyed by Id:
var user = // get some user
var dataContext = // your DB context
const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic
| BindingFlags.Public;
object commonDataServices = typeof(DataContext)
.GetField("services", AllInstance)
.GetValue(dataContext);
object identifier = commonDataServices.GetType()
.GetProperty("IdentityManager", AllInstance)
.GetValue(commonDataServices, null);
MethodInfo find = identifier.GetType().GetMethod("Find", AllInstance);
var metaType = dataContext.Mapping.GetMetaType(typeof(User));
object[] keys = new object[] { user.Id };
var user2 = (User)find.Invoke(identifier, new object[] { metaType, keys });
bool pass = ReferenceEquals(user, user2);
Pretty-much every access is non-public; I would expect this to suck performance-wise unless you use DynamicMethod to spoof access from another type.
And as a DynamicMethod version:
(yes, I'm hard-coding to an int key... you could make it any single-value by replacing the int with object, and just drop the OpCodes.Box, typeof(int) - or you could make it a params object[] argument and pass it in directly)
static readonly Func<DataContext, Type, int, object> identityLookup = BuildIdentityLookup();
static Func<DataContext, Type, int, object> BuildIdentityLookup()
{
var quickFind = new DynamicMethod("QuickFind", typeof(object), new Type[] { typeof(DataContext), typeof(Type), typeof(int) }, typeof(DataContext), true);
var il = quickFind.GetILGenerator();
const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
il.Emit(OpCodes.Ldarg_0); // DB
var services = typeof(DataContext).GetField("services", AllInstance);
il.Emit(OpCodes.Ldfld, services); // services
var identifier = services.FieldType.GetProperty("IdentityManager", AllInstance);
il.EmitCall(OpCodes.Callvirt, identifier.GetGetMethod(true), null); // identifier
il.Emit(OpCodes.Ldarg_0); // identifier DB
var mapping = typeof(DataContext).GetProperty("Mapping");
il.EmitCall(OpCodes.Callvirt, mapping.GetGetMethod(), null); // identifier mapping
il.Emit(OpCodes.Ldarg_1); // identifier mapping type
il.EmitCall(OpCodes.Callvirt, mapping.PropertyType.GetMethod("GetMetaType"), null); // identifier metatype
il.Emit(OpCodes.Ldc_I4_1); // identifier metatype 1
il.Emit(OpCodes.Newarr, typeof(object)); // identifier metatype object[]
il.Emit(OpCodes.Dup); // identifier metatype object[] object[]
il.Emit(OpCodes.Ldc_I4_0); // identifier metatype object[] object[] 0
il.Emit(OpCodes.Ldarg_2); // identifier metatype object[] object[] 0 id
il.Emit(OpCodes.Box, typeof(int)); // identifier metatype object[] object[] 0 boxed-id
il.Emit(OpCodes.Stelem_Ref); // identifier metatype object[]
il.EmitCall(OpCodes.Callvirt, identifier.PropertyType.GetMethod("Find", AllInstance), null); // object
il.Emit(OpCodes.Ret);
return (Func<DataContext, Type, int, object>)quickFind.CreateDelegate(typeof(Func<DataContext, Type, int, object>));
}

Reflection on a static overloaded method using an out parameter

I'm having some issues with invoking an overloaded static method with an out parameter via reflection and would appreciate some pointers.
I'm looking to dynamically create a type like System.Int32 or System.Decimal, and then invoke the static TryParse(string, out x) method on it.
The below code has two issues:
t.GetMethod("TryParse", new Type[] { typeof(string), t } ) fails to return the MethodInfo I expect
mi.Invoke(null, new object[] { value.ToString(), concreteInstance }) appears to succeed but doesn't set the out param concreteInstance to the parsed value
Interwoven into this function you can see some temporary code demonstrating what should happen if the type parameter was set to System.Decimal.
public static object Cast(object value, string type)
{
Type t = Type.GetType(type);
if (t != null)
{
object concreteInstance = Activator.CreateInstance(t);
decimal tempInstance = 0;
List<MethodInfo> l = new List<MethodInfo>(t.GetMethods(BindingFlags.Static | BindingFlags.Public));
MethodInfo mi;
mi = t.GetMethod("TryParse", new Type[] { typeof(string), t } ); //this FAILS to get the method, returns null
mi = l.FirstOrDefault(x => x.Name == "TryParse" && x.GetParameters().Length == 2); //ugly hack required because the previous line failed
if (mi != null)
{
try
{
bool retVal = decimal.TryParse(value.ToString(), out tempInstance);
Console.WriteLine(retVal.ToString()); //retVal is true, tempInstance is correctly set
object z = mi.Invoke(null, new object[] { value.ToString(), concreteInstance });
Console.WriteLine(z.ToString()); //z is true, but concreteInstance is NOT set
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
return concreteInstance;
}
return value;
}
What do I need to do to ensure that my t.GetMethod() call returns the correct MethodInfo? What do I need to do to have concreteInstance correctly set in my mi.Invoke() call?
I know there are a bunch of questions on this topic, but most of them involve static generic methods or static methods that are not overloaded. This question is similar but not a duplicate.
You need to use the right BindingFlags and use Type.MakeByRefType for out and ref parameters. One second, and I'll have a code sample for you.
For example,
MethodInfo methodInfo = typeof(int).GetMethod(
"TryParse",
BindingFlags.Public | BindingFlags.Static,
Type.DefaultBinder,
new[] { typeof(string), typeof(int).MakeByRefType() },
null
);
I should point out that invoking this is a little tricky too. Here's how you do it.
string s = "123";
var inputParameters = new object[] { "123", null };
methodInfo.Invoke(null, inputParameters);
Console.WriteLine((int)inputParameters[1]);
The first null is because we are invoking a static method (there is no object "receiving" this invocation). The null in inputParameters will be "filled" for us by TryParse with the result of the parse (it's the out parameter).

Categories