Return 重载失败
Return overload fails
我正在关注这篇小文章:https://github.com/Readify/Neo4jClient/wiki/cypher 但我是从 Powershell 进行的。所以我到目前为止是
[System.Reflection.Assembly]::LoadFrom("C:\...\Newtonsoft.Json.6.0.3\lib\net40\NewtonSoft.Json.dll")
[System.Reflection.Assembly]::LoadFrom("C:\...\Neo4jClient.1.0.0.662\lib\net40\Neo4jClient.dll")
$neo = new-object Neo4jClient.GraphClient(new-object Uri("http://localhost:7474/db/data"))
$q=$neo.Cypher.Match("n").Return({param($m) $m});
我的意思是检索数据库中的所有节点。示例中显示的 Return()
方法需要一个 lambda 表达式作为参数,这在 Powershell 中将是一个代码块,但是,我收到以下错误:
Cannot find an overload for "Return" and the argument count: "1". At
line:1 char:1
+ $q=$neo.Cypher.Match("n").Return({param($m) $m});
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
我哪里错了?
*更新我*
根据下面@PetSerAl 提供的解释,我已经取得了一些进展,但我仍然卡住了。下面我将引用编写的 (c#),然后显示等效的 powershell。首先我们声明一个 class
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
我的class有点不同
Add-Type -TypeDefinition "public class Project { public string Code; public string Name; public string Parent; public string Lifespan; }"
他们的 Cypher
MATCH (user:User)
RETURN user
他们的c#
graphClient.Cypher
.Match("(user:User)")
.Return(user => user.As<User>())
.Results
现在我的密码
MATCH (n:Project)
RETURN n
...最后,我对 powershell 的尝试:
$exp = [System.Linq.Expressions.Expression]
$p = $exp::Constant("Project")
$fn = $exp::TypeAs($p, (new-object Project).GetType())
$return = $exp::Lambda([Func[Project]], $fn, $p)
$neo.Cypher.Match("n").Return($return)
但是我得到一个错误
Exception calling "Return" with "1" argument(s): "The expression must
be constructed as either an object initializer (for example: n => new
MyResultType { Foo = n.Bar }), an anonymous type initializer (for
example: n => new { Foo = n.Bar }), a method call (for example: n =>
n.Count()), or a member accessor (for example: n => n.As().Bar).
You cannot supply blocks of code (for example: n => { var a = n + 1;
return a; }) or use constructors with arguments (for example: n => new
Foo(n)). If you're in F#, tuples are also supported. Parameter name:
expression" At line:1 char:1
+ $neo.Cypher.Match("n").Return($return)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
这一次,实际上非常清楚易懂。所以我想要的是一个方法调用,例如n => n.Count()
显然没有实现。
帮助?
*更新二*
因此,继续从 powershell 开始 neo4j 的曲折路径,我尝试了@PetSerAl 的第二种方法并取得了一些进展。这是我设法写的:
$neopath = "C:\[...]\Neo4jClient.dll"
Add-Type -ReferencedAssemblies $neopath -TypeDefinition @"
using System;
using System.Linq.Expressions;
using Neo4jClient.Cypher;
public class Project {
public string Code;
public string Name;
public string Parent;
public string Lifespan;
};
public static class NeoExp {
public static readonly Expression<Func<Neo4jClient.Cypher.ICypherResultItem,Project>> GetProject = (n) => n.As<Project>();
}
"@
现在允许我做:
$neo.Cypher.Match("n:Project").Return([NeoExp]::GetProject)
这奇迹般地奏效了!除了它没有给我带来任何数据:
Results ResultsAsync Query Client
------- ------------ ----- ------
Neo4jClient.Cypher.CypherQ... Neo4jClient.GraphClient
而且我知道我在数据库中有项目...所以现在可能是什么问题?
*更新三*
哇,太接近了,但还没有完成。根据@PetSerAl 的最新建议。我试过了:
$neo.Cypher.Match("n:Project").Return([NeoExp]::GetProject).get_Results()
产生了一个说明错误:
Exception calling "get_Results" with "0" argument(s): "The graph
client is not connected to the server. Call the Connect method first."
所以我首先需要做的很清楚:
$neo.Connect()
此外,我需要在查询的匹配子句周围加上括号:
$neo.Cypher.Match("(n:Project)").Return([NeoExp]::GetProject)
现在我在 .Results
字段中得到了预期的 27 个结果...但是,结果都是空白的。所以我认为这可能与 n.As<Project>()
有关,我的 class 可能没有正确定义并且失败了。有什么想法吗?
* 更新 IV *
好的,知道了。 Project
class 需要有属性,而不是字段:
public class Project {
public string Code { get; set; }
public string Name { get; set; }
public string Parent { get; set; }
public string Lifespan { get; set; }
};
就是这样。我有数据。是的!!!
@PetSelAl:我欠你一杯啤酒
我知道这不是您要的,甚至可能不是您想要的,但您可以 create your own C# class right inside PowerShell using Add-Type
。如果您编写的内容依赖于大量特定于 C# 的内容,那么以这种方式实现并提供可在 PowerShell 代码中使用的简单方法可能会更容易。
这个例子直接取自上面的link:
$source = @"
public class BasicTest
{
public static int Add(int a, int b)
{
return (a + b);
}
public int Multiply(int a, int b)
{
return (a * b);
}
}
"@
Add-Type -TypeDefinition $source
[BasicTest]::Add(4, 3)
$basicTestObject = New-Object BasicTest
$basicTestObject.Multiply(5, 2)
我只能说你用错了。你的对象结构应该是你的 Neo4jClient
对象,它应该有一些属性和方法。我很确定 Return
是 属性,而不是方法。所以我在想更像是:
$neo = new-object Neo4jClient.GraphClient(new-object Uri("http://localhost:7474/db/data"))
$neo.Cypher.Match = "n"
$neo.Cypher.Return = {param($m) $m}
$q = $neo.Cypher.Results()
在那里你创建了你的对象,你定义了Match
过滤器,定义了你想要的return(从它的外观来看一切),然后将结果存储在$q
变量。我很确定这应该与以下内容相同:
SELECT * FROM Uri("http://localhost:7474/db/data")) WHERE "n"
我也有点想知道你的 Match
标准,因为他们似乎在他们的例子中指定了 property/value 对,而你只给出了两个中的一个。如果失败,我强烈建议您执行 $neo.Cypher | Get-Member
以查看您拥有的属性、它们的类型以及您拥有的方法。
编辑: 好的,所以我确实查看了 link。我还下载了这些库,将它们加载到 PowerShell 中,并查看了 .Net 对象。 Return 确实是一种方法,它的重载是荒谬的。它有 37 个重载,其中最长的将近 750 个字符。大部分都是ICypherResultItem
表达式,但最简单的是(string identity)
。我可以建议简单地尝试 Return("*")
?
Return
方法有两个问题:
- 它接受表达式树类型的参数,而不是编译委托类型。而且 PowerShell 没有从
ScriptBlock
创建表达式树的简单方法。因此,您必须手动创建表达式树或使用 string
重载。
string
重载不允许 PowerShell 推断方法的泛型参数,并且 PowerShell 语法不允许显式指定泛型参数。所以,PowerShell 不能直接调用 Return
方法的 string
重载。您必须使用一些解决方法来调用它,例如,通过 Reflection
. 调用它
示例如何在 PowerShell 中创建一个简单的表达式树 ((a,b) => a*2+b
):
# First way: messing with [System.Linq.Expressions.Expression]
$a=[System.Linq.Expressions.Expression]::Parameter([int],'a')
$b=[System.Linq.Expressions.Expression]::Parameter([int],'b')
=[System.Linq.Expressions.Expression]::Constant(2)
$Body=[System.Linq.Expressions.Expression]::Add([System.Linq.Expressions.Expression]::Multiply($a,),$b)
$Sum=[System.Linq.Expressions.Expression]::Lambda([Func[int,int,int]],$Body,$a,$b)
$Sum
# Second way: using help of C#
Add-Type -TypeDefinition @'
using System;
using System.Linq.Expressions;
public static class MyExpression {
public static readonly Expression<Func<int,int,int>> Sum=(a,b) => a*2+b;
}
'@
[MyExpression]::Sum
非常感谢@PetSerAl,他从本质上很好地解释了这个问题,并且在解决问题时牵着我的手。
重申一下,问题是 Powershell 没有调用泛型方法的内置机制,Neo4jClient 库的 .Return
方法重载都是泛型的。具体来说,Powershell 不提供提供方法类型的方法。
所以有几种方法可以解决这个问题:
一种解决方案是使用反射来进行调用,但任务有点棘手。值得庆幸的是,该方法已通过 tech net 上的一个项目得到解决。参见:https://gallery.technet.microsoft.com/scriptcenter/Invoke-Generic-Methods-bf7675af
@PetSerAl 的回复中建议的第二个解决方案需要一点帮助,但在@ChrisSkardon 的帮助下我让它工作了。看这里:
和第三个解决方案(请参阅原始 post 中的更新)依赖于使用可以调用通用方法的方法创建 c# class
我希望在 Neo4jClient 的 wiki 中记录此解决方案,我希望此处记录的工作对其他人有所帮助。再次感谢@PetSerAl 的所有帮助
我正在关注这篇小文章:https://github.com/Readify/Neo4jClient/wiki/cypher 但我是从 Powershell 进行的。所以我到目前为止是
[System.Reflection.Assembly]::LoadFrom("C:\...\Newtonsoft.Json.6.0.3\lib\net40\NewtonSoft.Json.dll")
[System.Reflection.Assembly]::LoadFrom("C:\...\Neo4jClient.1.0.0.662\lib\net40\Neo4jClient.dll")
$neo = new-object Neo4jClient.GraphClient(new-object Uri("http://localhost:7474/db/data"))
$q=$neo.Cypher.Match("n").Return({param($m) $m});
我的意思是检索数据库中的所有节点。示例中显示的 Return()
方法需要一个 lambda 表达式作为参数,这在 Powershell 中将是一个代码块,但是,我收到以下错误:
Cannot find an overload for "Return" and the argument count: "1". At line:1 char:1 + $q=$neo.Cypher.Match("n").Return({param($m) $m}); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodCountCouldNotFindBest
我哪里错了?
*更新我*
根据下面@PetSerAl 提供的解释,我已经取得了一些进展,但我仍然卡住了。下面我将引用编写的 (c#),然后显示等效的 powershell。首先我们声明一个 class
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
我的class有点不同
Add-Type -TypeDefinition "public class Project { public string Code; public string Name; public string Parent; public string Lifespan; }"
他们的 Cypher
MATCH (user:User)
RETURN user
他们的c#
graphClient.Cypher
.Match("(user:User)")
.Return(user => user.As<User>())
.Results
现在我的密码
MATCH (n:Project)
RETURN n
...最后,我对 powershell 的尝试:
$exp = [System.Linq.Expressions.Expression]
$p = $exp::Constant("Project")
$fn = $exp::TypeAs($p, (new-object Project).GetType())
$return = $exp::Lambda([Func[Project]], $fn, $p)
$neo.Cypher.Match("n").Return($return)
但是我得到一个错误
Exception calling "Return" with "1" argument(s): "The expression must be constructed as either an object initializer (for example: n => new MyResultType { Foo = n.Bar }), an anonymous type initializer (for example: n => new { Foo = n.Bar }), a method call (for example: n => n.Count()), or a member accessor (for example: n => n.As().Bar). You cannot supply blocks of code (for example: n => { var a = n + 1; return a; }) or use constructors with arguments (for example: n => new Foo(n)). If you're in F#, tuples are also supported. Parameter name: expression" At line:1 char:1 + $neo.Cypher.Match("n").Return($return) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ArgumentException
这一次,实际上非常清楚易懂。所以我想要的是一个方法调用,例如n => n.Count()
显然没有实现。
帮助?
*更新二*
因此,继续从 powershell 开始 neo4j 的曲折路径,我尝试了@PetSerAl 的第二种方法并取得了一些进展。这是我设法写的:
$neopath = "C:\[...]\Neo4jClient.dll"
Add-Type -ReferencedAssemblies $neopath -TypeDefinition @"
using System;
using System.Linq.Expressions;
using Neo4jClient.Cypher;
public class Project {
public string Code;
public string Name;
public string Parent;
public string Lifespan;
};
public static class NeoExp {
public static readonly Expression<Func<Neo4jClient.Cypher.ICypherResultItem,Project>> GetProject = (n) => n.As<Project>();
}
"@
现在允许我做:
$neo.Cypher.Match("n:Project").Return([NeoExp]::GetProject)
这奇迹般地奏效了!除了它没有给我带来任何数据:
Results ResultsAsync Query Client
------- ------------ ----- ------
Neo4jClient.Cypher.CypherQ... Neo4jClient.GraphClient
而且我知道我在数据库中有项目...所以现在可能是什么问题?
*更新三*
哇,太接近了,但还没有完成。根据@PetSerAl 的最新建议。我试过了:
$neo.Cypher.Match("n:Project").Return([NeoExp]::GetProject).get_Results()
产生了一个说明错误:
Exception calling "get_Results" with "0" argument(s): "The graph client is not connected to the server. Call the Connect method first."
所以我首先需要做的很清楚:
$neo.Connect()
此外,我需要在查询的匹配子句周围加上括号:
$neo.Cypher.Match("(n:Project)").Return([NeoExp]::GetProject)
现在我在 .Results
字段中得到了预期的 27 个结果...但是,结果都是空白的。所以我认为这可能与 n.As<Project>()
有关,我的 class 可能没有正确定义并且失败了。有什么想法吗?
* 更新 IV *
好的,知道了。 Project
class 需要有属性,而不是字段:
public class Project {
public string Code { get; set; }
public string Name { get; set; }
public string Parent { get; set; }
public string Lifespan { get; set; }
};
就是这样。我有数据。是的!!!
@PetSelAl:我欠你一杯啤酒
我知道这不是您要的,甚至可能不是您想要的,但您可以 create your own C# class right inside PowerShell using Add-Type
。如果您编写的内容依赖于大量特定于 C# 的内容,那么以这种方式实现并提供可在 PowerShell 代码中使用的简单方法可能会更容易。
这个例子直接取自上面的link:
$source = @"
public class BasicTest
{
public static int Add(int a, int b)
{
return (a + b);
}
public int Multiply(int a, int b)
{
return (a * b);
}
}
"@
Add-Type -TypeDefinition $source
[BasicTest]::Add(4, 3)
$basicTestObject = New-Object BasicTest
$basicTestObject.Multiply(5, 2)
我只能说你用错了。你的对象结构应该是你的 Neo4jClient
对象,它应该有一些属性和方法。我很确定 Return
是 属性,而不是方法。所以我在想更像是:
$neo = new-object Neo4jClient.GraphClient(new-object Uri("http://localhost:7474/db/data"))
$neo.Cypher.Match = "n"
$neo.Cypher.Return = {param($m) $m}
$q = $neo.Cypher.Results()
在那里你创建了你的对象,你定义了Match
过滤器,定义了你想要的return(从它的外观来看一切),然后将结果存储在$q
变量。我很确定这应该与以下内容相同:
SELECT * FROM Uri("http://localhost:7474/db/data")) WHERE "n"
我也有点想知道你的 Match
标准,因为他们似乎在他们的例子中指定了 property/value 对,而你只给出了两个中的一个。如果失败,我强烈建议您执行 $neo.Cypher | Get-Member
以查看您拥有的属性、它们的类型以及您拥有的方法。
编辑: 好的,所以我确实查看了 link。我还下载了这些库,将它们加载到 PowerShell 中,并查看了 .Net 对象。 Return 确实是一种方法,它的重载是荒谬的。它有 37 个重载,其中最长的将近 750 个字符。大部分都是ICypherResultItem
表达式,但最简单的是(string identity)
。我可以建议简单地尝试 Return("*")
?
Return
方法有两个问题:
- 它接受表达式树类型的参数,而不是编译委托类型。而且 PowerShell 没有从
ScriptBlock
创建表达式树的简单方法。因此,您必须手动创建表达式树或使用string
重载。 string
重载不允许 PowerShell 推断方法的泛型参数,并且 PowerShell 语法不允许显式指定泛型参数。所以,PowerShell 不能直接调用Return
方法的string
重载。您必须使用一些解决方法来调用它,例如,通过Reflection
. 调用它
示例如何在 PowerShell 中创建一个简单的表达式树 ((a,b) => a*2+b
):
# First way: messing with [System.Linq.Expressions.Expression]
$a=[System.Linq.Expressions.Expression]::Parameter([int],'a')
$b=[System.Linq.Expressions.Expression]::Parameter([int],'b')
=[System.Linq.Expressions.Expression]::Constant(2)
$Body=[System.Linq.Expressions.Expression]::Add([System.Linq.Expressions.Expression]::Multiply($a,),$b)
$Sum=[System.Linq.Expressions.Expression]::Lambda([Func[int,int,int]],$Body,$a,$b)
$Sum
# Second way: using help of C#
Add-Type -TypeDefinition @'
using System;
using System.Linq.Expressions;
public static class MyExpression {
public static readonly Expression<Func<int,int,int>> Sum=(a,b) => a*2+b;
}
'@
[MyExpression]::Sum
非常感谢@PetSerAl,他从本质上很好地解释了这个问题,并且在解决问题时牵着我的手。
重申一下,问题是 Powershell 没有调用泛型方法的内置机制,Neo4jClient 库的 .Return
方法重载都是泛型的。具体来说,Powershell 不提供提供方法类型的方法。
所以有几种方法可以解决这个问题:
一种解决方案是使用反射来进行调用,但任务有点棘手。值得庆幸的是,该方法已通过 tech net 上的一个项目得到解决。参见:https://gallery.technet.microsoft.com/scriptcenter/Invoke-Generic-Methods-bf7675af
@PetSerAl 的回复中建议的第二个解决方案需要一点帮助,但在@ChrisSkardon 的帮助下我让它工作了。看这里:
和第三个解决方案(请参阅原始 post 中的更新)依赖于使用可以调用通用方法的方法创建 c# class
我希望在 Neo4jClient 的 wiki 中记录此解决方案,我希望此处记录的工作对其他人有所帮助。再次感谢@PetSerAl 的所有帮助