返回重载失败

时间:2015-05-19 00:04:25

标签: powershell neo4j neo4jclient

我跟着这个小小的写作: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中它将是一个代码块,但是,我收到以下错误:

  

无法找到"返回"和参数计数:" 1"。在   line:1 char:1   + $ q = $ neo.Cypher.Match(" n")。返回({param($ m)$ m});   + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:NotSpecified:(:) [],MethodException       + FullyQualifiedErrorId:MethodCountCouldNotFindBest

我哪里错了?

*更新I *

根据@PetSerAl提供的解释,我已经设法进一步,但我仍然卡住了。下面我将引用写下来(c#),然后显示等效的powershell。首先我们声明一个类

public class User
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

我的班级略有不同

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)

但是我收到了错误

  

异常通话&#34;返回&#34;用&#34; 1&#34;参数:&#34;表达式必须   被构造为对象初始化器(例如:n =&gt; new   MyResultType {Foo = n.Bar}),一个匿名类型的初始化器(for   例如:n =&gt; new {Foo = n.Bar}),方法调用(例如:n =&gt;   n.Count()),或成员访问者(例如:n =&gt; n.As()。Bar)。   您无法提供代码块(例如:n =&gt; {var a = n + 1;   返回; })或使用带参数的构造函数(例如:n =&gt; new   FOO(N))。如果你在F#中,也支持元组。参数名称:   表达&#34;在行:1个字符:1   + $ neo.Cypher.Match(&#34; n&#34;)。返回($ return)   + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:NotSpecified:(:) [],MethodInvocationException       + FullyQualifiedErrorId:ArgumentException

这一次,实际上是非常明确和可以理解的。所以我想要的是方法调用,例如n => n.Count()显然没有实现这一目标。

帮助?

*更新II *

所以,继续使用来自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

我知道我在数据库中有项目......那么现在的问题是什么呢?

*更新III *

哇,好近,但还没完成。根据@PetSerAl的最新建议。我试过了:

$neo.Cypher.Match("n:Project").Return([NeoExp]::GetProject).get_Results()

产生了一个明显的错误:

  

异常调用&#34; get_Results&#34;用&#34; 0&#34;参数:&#34;图表   客户端未连接到服务器。首先调用Connect方法。&#34;

所以说清楚我首先要做的事情:

$neo.Connect()

另外,我需要围绕查询匹配子句的括号:

$neo.Cypher.Match("(n:Project)").Return([NeoExp]::GetProject)

现在我在.Results字段中按预期收到了27个结果...但是,结果都是空白的。所以我想也许它与n.As<Project>()有关,也许我的班级没有正确定义而且失败了。有什么想法吗?

*更新IV *

好的,明白了。 Project类需要具有属性,而不是字段:

    public class Project {
        public string Code { get; set; }
        public string Name { get; set; }
        public string Parent { get; set; }
        public string Lifespan { get; set; }
    };

就是这样。我有数据。酵母!!!

@PetSelAl:我欠你一杯啤酒

4 个答案:

答案 0 :(得分:2)

Return方法存在两个问题:

  1. 它接受表达式树类型的参数,而不是编译委托类型。而PowerShell没有一种简单的方法来从ScriptBlock创建表达式树。因此,您必须手动创建表达式树或使用string重载。
  2. string重载不允许PowerShell推断方法的泛型参数,而PowerShell语法不允许显式指定泛型参数。因此,PowerShell无法直接调用string方法的Return重载。您必须使用一些变通方法来调用它,例如,通过Reflection调用它。
  3. 示例如何在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')
    $2=[System.Linq.Expressions.Expression]::Constant(2)
    
    $Body=[System.Linq.Expressions.Expression]::Add([System.Linq.Expressions.Expression]::Multiply($a,$2),$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
    

答案 1 :(得分:1)

我知道这并不是你所要求的,甚至可能不是你想要的,但你可以create your own C# class right inside PowerShell using Add-Type。以这种方式实现它可能更容易,并提供可在PowerShell代码中使用的简单方法,如果您正在编写的内容依赖于大量C#特定的东西。

此示例直接来自上面的链接:

$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)

答案 2 :(得分:0)

我能说的最好的就是你错了。您的对象结构应该是您的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过滤器,定义了你希望它返回什么(从它的外观来看),然后将结果存储在$q变量中。我很确定它应该与:

相同
SELECT * FROM Uri("http://localhost:7474/db/data")) WHERE "n"

我也对你的Match标准感到好奇,因为他们似乎在他们的例子中指定了属性/值对,你只需要给出其中一个。如果失败,我强烈建议您使用$neo.Cypher | Get-Member查看您拥有的属性,他们输入的内容以及您拥有的方法。

编辑:好的,所以我确实看了一下这个链接。我还下载了库,将它们加载到PowerShell中,然后查看.Net对象。返回确实是一种方法,它的重载是荒谬的。它有37个重载,其中最长的是近750个字符。其中大多数是ICypherResultItem表达式,但最简单的是(string identity)。我建议你只是尝试Return("*")

答案 3 :(得分:0)

一百万感谢@PetSerAl,他从本质上解释了这个问题,并且通过决议来解决问题。

要重申,问题是Powershell没有内置机制来调用泛型方法,而Neo4jClient库的.Return方法重载都是通用的。具体而言,Powershell无法提供该方法的类型。

所以有几种方法可以解决这个问题:

  • 一个解决方案是使用反射来进行调用,但任务有点棘手。谢天谢地,这个方法已经被科技网上的一个项目所解决。见:https://gallery.technet.microsoft.com/scriptcenter/Invoke-Generic-Methods-bf7675af

  • 在@ PetSerAl的回复中提出的第二个解决方案需要一些帮助,但在@ ChrisSkardon的帮助下,我得到了它的工作。见这里:Constructing a method call

  • 和第三个解决方案(参见原始帖子中的更新),它依赖于创建一个c#类,其方法可以调用泛型方法

我希望在Wiki中为Neo4jClient记录这个解决方案,我希望这里记录的努力对其他人有帮助。再次感谢@PetSerAl提供所有帮助