调用通用反射方法时对象引用未设置为对象的实例
Object reference not set to an instance of an object when Invoking generic reflective method
所以这个问题比较迷惑。而且它相当复杂和抽象,所以我将尽力解释它。
我有 3 classes LinkedIn
、Facebook
和 Twitter
。它们都继承自一个公共基础 class SocialBase
,它只有一个 属性: uuid
并且这个 属性 仅用于我们可以找到实际类型在数据库中。
所以我有一个接受 Profile
class 的函数,它包含所有 LinkedIn
、Facebook
和 Twitter
表的外键,以及一个枚举值,它将告诉我们是否要查找 LinkedIn
、Facebook
或 Twitter
外键
public static async Task UnlinkSocialAccountFromProfile(Profile prof, SocialNetworks provider)
{
//TYPE variable of LinkedIn, Facebook, or Twitter
var handler = HandlerMapping[provider];
//client is MobileServiceClient
var method = client.GetType().GetMethod("GetTable", Type.EmptyTypes);
//MobileServiceClient.GetTable<handler>()
var generic = method.MakeGenericMethod(handler);
//IMobileServiceTable<handler>
var table = generic.Invoke(client, null);
//Profile has 3 foreign keys, LinkedinUUID, FacebookUUID, TwitterUUID, we want the <handler>UUID
string propertyValue = prof.GetType().GetProperty(handler.Name + "UUID").GetValue(prof) as string;
//Invoke Extension method with our generic types
var genMethod =
typeof (Extensions).GetMethod("FilterByNamedProperty")
.MakeGenericMethod(table.GetType().GetGenericArguments()[0], propertyValue.GetType());
//Get the List<handler> that results from our query
var result = await (Task<List<Linkedin>>)(genMethod.Invoke(null, new [] {table, "uuid", propertyValue}));
//var result = await (table as IMobileServiceTable<SocialBase>).FilterByNamedProperty("uuid", propertyValue);
await new SocialResources().DeleteIfExists((result as IList<SocialBase>)[0]);
}
所以我在这里做的是获取 class 的 Type
,因此这将是 SocialBase
子 class 之一。对于这个特定的示例,我知道我将寻找 LinkedIn
类型。所以在获得类型 LinkedIn
之后,我需要从我的 MobileServiceTable
调用泛型方法,所以通常它看起来像 MobileServiceTable.GetTable<LinkedIn>()
但是由于反射我们必须绕过这个更长的路线。
在获得 IMobileServiceTable<LinkedIn>
的返回实例后,我得到了我正在寻找的外键的值。在这种情况下,它将被称为 LinkedInUUID
。现在棘手的部分来了。我有这个扩展方法可以为我构造我的查询表达式,因为它必须是 Expression<Func<LinkedIn, bool>>
类型
public async static Task<List<TSource>> FilterByNamedProperty<TSource, TValue>(this IMobileServiceTable<TSource> source, string propertyName, TValue value)
{
// uuid
var property = typeof(TSource).GetProperty(propertyName);
// (TSource)p
var parExp = Expression.Parameter(typeof(TSource));
//p.uuid
var methodExp = Expression.Property(parExp, property);
// value
var constExp = Expression.Constant(value, typeof(TValue));
// p.uuid == value
var binExp = Expression.Equal(methodExp, constExp);
// p => p.uuid == value
var lambda = Expression.Lambda<Func<TSource, bool>>(binExp, parExp);
return await source.Where(lambda).ToListAsync();
}
我相信评论在解释每个语句出现时的构建过程方面做得很好。然而,一旦我们到达 return await ...
应用程序就会崩溃。这是该行之前的输出和紧随其后的错误。
IMobileServiceTable<TSource> source = {Microsoft.WindowsAzure.MobileServices.MobileServiceTable<SocialConnect.Linkedin>}
(正确)
propertyName = uuid
(正确)
TValue value = dscRJQSIxJaEfd
(正确)
我强烈感觉问题出在我的 lambda
表达式上,但如果我用 var test = await (source as IMobileServiceTable<Linkedin>).Where(p => p.uuid == (value as string)).ToListAsync();
行测试扩展,它工作得很好。但是,一旦我将其更改为使用 lambda
变量,我就会得到异常。 lambda 表达式的实际值是 {Param_0 => (Param_0.uuid == "dscRJQSIxJaEfd")}
,看起来是正确的
有什么想法吗?
编辑
抱歉,这是堆栈跟踪中的实际异常
`A first chance exception of type 'System.NullReferenceException' occurred in mscorlib.dll
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.GetTableMemberName(Expression expression, MobileServiceContractResolver contractResolver)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.VisitMemberAccess(MemberExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Visit(Expression node)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.VisitBinary(BinaryExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Visit(Expression node)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Compile(Expression expression, MobileServiceContractResolver contractResolver)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.AddFilter(MethodCallExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.VisitMethodCall(MethodCallExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.Visit(Expression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.Translate()
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryProvider.Compile[T](IMobileServiceTableQuery1 query)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryProvider.<Execute>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQuery1.<ToListAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at SocialConnect.Models.Extensions.<FilterByNamedProperty>d__22.MoveNext() in MobileServiceSample\MobileServiceSample\Extensions.cs:line 55`
好的,我终于解决了这个问题。显然问题不在于查询或我正在做的任何事情,而在于 SocialBase
class。我一直在用它来制作方法,我知道泛型类型 TEntity
会有一个 uuid
属性,所以我可以很容易地在任何数据库中找到它。但我猜该字段没有正确序列化,这就是导致 NullReferenceException
的原因。在删除基础 class 并反思地找到 属性 和值之后,一切都开始正常工作。
我不明白为什么它之前不能正常工作,因为在此之前我一直在使用基础 SocialBase
class 很多情况。
所以这个问题比较迷惑。而且它相当复杂和抽象,所以我将尽力解释它。
我有 3 classes LinkedIn
、Facebook
和 Twitter
。它们都继承自一个公共基础 class SocialBase
,它只有一个 属性: uuid
并且这个 属性 仅用于我们可以找到实际类型在数据库中。
所以我有一个接受 Profile
class 的函数,它包含所有 LinkedIn
、Facebook
和 Twitter
表的外键,以及一个枚举值,它将告诉我们是否要查找 LinkedIn
、Facebook
或 Twitter
外键
public static async Task UnlinkSocialAccountFromProfile(Profile prof, SocialNetworks provider)
{
//TYPE variable of LinkedIn, Facebook, or Twitter
var handler = HandlerMapping[provider];
//client is MobileServiceClient
var method = client.GetType().GetMethod("GetTable", Type.EmptyTypes);
//MobileServiceClient.GetTable<handler>()
var generic = method.MakeGenericMethod(handler);
//IMobileServiceTable<handler>
var table = generic.Invoke(client, null);
//Profile has 3 foreign keys, LinkedinUUID, FacebookUUID, TwitterUUID, we want the <handler>UUID
string propertyValue = prof.GetType().GetProperty(handler.Name + "UUID").GetValue(prof) as string;
//Invoke Extension method with our generic types
var genMethod =
typeof (Extensions).GetMethod("FilterByNamedProperty")
.MakeGenericMethod(table.GetType().GetGenericArguments()[0], propertyValue.GetType());
//Get the List<handler> that results from our query
var result = await (Task<List<Linkedin>>)(genMethod.Invoke(null, new [] {table, "uuid", propertyValue}));
//var result = await (table as IMobileServiceTable<SocialBase>).FilterByNamedProperty("uuid", propertyValue);
await new SocialResources().DeleteIfExists((result as IList<SocialBase>)[0]);
}
所以我在这里做的是获取 class 的 Type
,因此这将是 SocialBase
子 class 之一。对于这个特定的示例,我知道我将寻找 LinkedIn
类型。所以在获得类型 LinkedIn
之后,我需要从我的 MobileServiceTable
调用泛型方法,所以通常它看起来像 MobileServiceTable.GetTable<LinkedIn>()
但是由于反射我们必须绕过这个更长的路线。
在获得 IMobileServiceTable<LinkedIn>
的返回实例后,我得到了我正在寻找的外键的值。在这种情况下,它将被称为 LinkedInUUID
。现在棘手的部分来了。我有这个扩展方法可以为我构造我的查询表达式,因为它必须是 Expression<Func<LinkedIn, bool>>
public async static Task<List<TSource>> FilterByNamedProperty<TSource, TValue>(this IMobileServiceTable<TSource> source, string propertyName, TValue value)
{
// uuid
var property = typeof(TSource).GetProperty(propertyName);
// (TSource)p
var parExp = Expression.Parameter(typeof(TSource));
//p.uuid
var methodExp = Expression.Property(parExp, property);
// value
var constExp = Expression.Constant(value, typeof(TValue));
// p.uuid == value
var binExp = Expression.Equal(methodExp, constExp);
// p => p.uuid == value
var lambda = Expression.Lambda<Func<TSource, bool>>(binExp, parExp);
return await source.Where(lambda).ToListAsync();
}
我相信评论在解释每个语句出现时的构建过程方面做得很好。然而,一旦我们到达 return await ...
应用程序就会崩溃。这是该行之前的输出和紧随其后的错误。
IMobileServiceTable<TSource> source = {Microsoft.WindowsAzure.MobileServices.MobileServiceTable<SocialConnect.Linkedin>}
(正确)
propertyName = uuid
(正确)
TValue value = dscRJQSIxJaEfd
(正确)
我强烈感觉问题出在我的 lambda
表达式上,但如果我用 var test = await (source as IMobileServiceTable<Linkedin>).Where(p => p.uuid == (value as string)).ToListAsync();
行测试扩展,它工作得很好。但是,一旦我将其更改为使用 lambda
变量,我就会得到异常。 lambda 表达式的实际值是 {Param_0 => (Param_0.uuid == "dscRJQSIxJaEfd")}
,看起来是正确的
有什么想法吗?
编辑 抱歉,这是堆栈跟踪中的实际异常
`A first chance exception of type 'System.NullReferenceException' occurred in mscorlib.dll
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.GetTableMemberName(Expression expression, MobileServiceContractResolver contractResolver)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.VisitMemberAccess(MemberExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Visit(Expression node)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.VisitBinary(BinaryExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Visit(Expression node)
at Microsoft.WindowsAzure.MobileServices.Query.FilterBuildingExpressionVisitor.Compile(Expression expression, MobileServiceContractResolver contractResolver)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.AddFilter(MethodCallExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.VisitMethodCall(MethodCallExpression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.Visit(Expression expression)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryTranslator1.Translate()
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryProvider.Compile[T](IMobileServiceTableQuery1 query)
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQueryProvider.<Execute>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at Microsoft.WindowsAzure.MobileServices.Query.MobileServiceTableQuery1.<ToListAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at SocialConnect.Models.Extensions.<FilterByNamedProperty>d__22.MoveNext() in MobileServiceSample\MobileServiceSample\Extensions.cs:line 55`
好的,我终于解决了这个问题。显然问题不在于查询或我正在做的任何事情,而在于 SocialBase
class。我一直在用它来制作方法,我知道泛型类型 TEntity
会有一个 uuid
属性,所以我可以很容易地在任何数据库中找到它。但我猜该字段没有正确序列化,这就是导致 NullReferenceException
的原因。在删除基础 class 并反思地找到 属性 和值之后,一切都开始正常工作。
我不明白为什么它之前不能正常工作,因为在此之前我一直在使用基础 SocialBase
class 很多情况。