LINQPad [扩展]方法


144

是否有人拥有LINQPad扩展方法和方法的完整列表,例如

.Dump()

SubmitChanges()

1
我投票结束这个问题是因为脱离话题,因为LINQPad是一个不断变化的工具,对这个问题有一个坚实而具体的最终答案将有很短的寿命。我建议将其关闭,以免引起其他工具的类似问题。
Lasse V. Karlsen

5
关于投票我没​​有什么要说的,但是我当然不同意结束这个答案。首先,仅查看问题的支持者,然后查看前两个评论的支持者。其次,约瑟夫的答案怎么会比最终答案少呢?他写了东西。最后,其他应用程序将Stackoverflow用于其文档。我一直使用LinqPad进行开发,制作C#和Linq查询的原型,运行SQL,执行Quick DBA任务,以及许多其他事情。因此,至少对我而言,答案肯定是关于主题的。
EoRaptor013 '18

3
重新结束:我为C#上的较早问题添加了一个以上答案,以提供一种更现代的技术,该技术自从回答问题以来已引入到该语言中。海事组织,我们应该期望随着技术的发展,本网站所代表的知识库会被修改和更新。将来的更新可能会折衷或使在特定时间点给出的答案无效的主题范围非常广泛:如果我们在可能发生的所有问题上都解决所有问题,则Stack Overflow将会是一个更加糟糕的资源!在这里,完整列表可能会成为部分列表,总比没有列表要好!
Bob Sammers

Answers:


255

LINQPad定义了两种扩展方法(在LINQPad.Extensions中),即Dump()Disassemble()Dump()使用LINQPad的输出格式化程序写入输出窗口,并重载以允许您指定标题:

typeof (int).Assembly.Dump ();
typeof (int).Assembly.Dump ("mscorlib");

您还可以指定最大递归深度以覆盖默认的5个级别:

typeof (int).Assembly.Dump (1);              // Dump just one level deep
typeof (int).Assembly.Dump (7);              // Dump 7 levels deep
typeof (int).Assembly.Dump ("mscorlib", 7);  // Dump 7 levels deep with heading

Disassemble()将任何方法反汇编为IL,以字符串形式返回输出:

typeof (Uri).GetMethod ("GetHashCode").Disassemble().Dump();

除了这两种扩展方法外,LINQPad.Util中还有一些有用的静态方法。这些以自动完成的方式记录在案,包括:

  • Cmd-执行Shell命令或外部程序
  • CreateXhtmlWriter-创建一个使用LINQPad的Dump()格式化程序的文本编写器
  • SqlOutputWriter-返回写入SQL输出窗口的文本编写器
  • GetMyQueriesGetSamples-返回代表您已保存的查询/示例的对象的集合(例如,使用“编辑” |“搜索全部”执行搜索)
  • 高亮 -包裹对象,以便在转储时以黄色突出显示
  • Horizo​​ntalRun-让您在同一行上转储一系列对象

LINQPad还提供了HyperLinq类。这有两个目的:第一个是显示普通的超链接:

new Hyperlinq ("www.linqpad.net").Dump();
new Hyperlinq ("www.linqpad.net", "Web site").Dump();
new Hyperlinq ("mailto:user@domain.com", "Email").Dump();

您可以将其与Util.HorizontalRun

Util.HorizontalRun (true,
  "Check out",
   new Hyperlinq ("http://stackoverflow.com", "this site"),
  "for answers to programming questions.").Dump();

结果:

此站点上查找有关编程问题的答案。

HyperLinq的第二个目的是动态构建查询:

// Dynamically build simple expression:
new Hyperlinq (QueryLanguage.Expression, "123 * 234").Dump();

// Dynamically build query:
new Hyperlinq (QueryLanguage.Expression, @"from c in Customers
where c.Name.Length > 3
select c.Name", "Click to run!").Dump();

您也可以在LINQPad中编写自己的扩展方法。转到“我的查询”,然后单击名为“我的扩展程序”的查询。所有查询均可访问此处定义的任何类型/方法:

void Main()
{
  "hello".Pascal().Dump();  
}

public static class MyExtensions
{
  public static string Pascal (this string s)
  {
    return char.ToLower (s[0]) + s.Substring(1);
  }
}

在4.46(.02)中,引入了新的类和方法

  • DumpContainer(类)
  • OnDemand(扩展方法)
  • Util.ProgressBar(类)

此外,Hyperlinq类现在支持一个Action委托,当您单击该链接时将调用该委托,从而使您可以在代码中对它进行响应,而不仅仅是链接到外部网页。

DumpContainer 是一个将块添加到输出窗口的类,该块可以替换其内容。

注意!记住.Dump()DumpContainer自己在适当的位置。

使用方法:

var dc = new DumpContainer();
dc.Content = "Test";
// further down in the code
dc.Content = "Another test";

OnDemand是一种扩展方法,该方法不会将其参数的内容输出到输出窗口,而是添加一个可单击的链接,该链接在单击时将用.Dump()参数的ed内容替换该链接。这对于有时需要的成本很高或占用大量空间的数据结构非常有用。

注意!记住在适当地点.Dump()打电话的结果OnDemand

要使用它:

Customers.OnDemand("Customers").Dump(); // description is optional

Util.ProgressBar 是一个类,可以在输出窗口中显示图形进度条,可以随着代码的继续进行更改。

注意!请记住.Dump()在适当位置的Util.ProgressBar对象。

要使用它:

var pb = new Util.ProgressBar("Analyzing data");
pb.Dump();
for (int index = 0; index <= 100; index++)
{
    pb.Percent = index;
    Thread.Sleep(100);
}

33
没有比作者本人的回答更好的了!
约翰,2010年

1
Joe,我实际上也想对一些图形工作进行原型设计,然后想转储位图。对于这类工作,使用Show方法将非常有用,您需要在其中进行一些可视化处理,处理图形,图像等。可能会为以后的其他一些类型提供整洁的可视化处理。
Bent Rasmussen 2010年

...实际上,只要您可以将图形发送到输出面板,我们就可以自己构建其余部分的扩展。
Bent Rasmussen

3
4.26 beta版允许您通过调用Util.RawHtml将XHTML注入输出流。请访问www.linqpad.net/beta.aspx(或等待几天以获取RTM)。
乔·阿尔巴哈里

1
亚历克斯(Alex)-要让1件事情上线,请使用Util.Horizo​​ntalRun
Joe Albahari

131

除了众所周知的myQuery.Dump("Query result:"),还有另一个要提到的功能是Util类:它包含许多非常方便的方法(我已经提到了其中的一些方法,但是还有很多)。

同样有趣的是,您可以修改Dump()工作方式

最后,我将向您展示如何使用或来使更改永久化(即,插入,更新,删除 LINQ查询),以及如何访问LinqPad的内部连接对象。SubmitChanges()SaveChanges()

并且将其四舍五入,我将向您展示如何在LinqPad内创建简单的2d图形(绘制线条,位图函数)。

因此,这是一组内置的LinqPad功能(根据我对该工具的经验):


。倾倒()

(LinqPad v5.03.08及更高版本中可用的参数)

所有LinqPad用户都知道并喜欢.Dump()扩展方法,该方法消耗并打印(几乎)所有内容。

但是您知道有几个可用的参数吗?看一下以下代码片段:

var obj=new { a="Hello", b=5, c="World", d=new { y=5, z=10 } };
obj.Dump(description: "1st example", depth: 5, toDataGrid: false, exclude: "b,d");
obj.Dump("2nd example", exclude: "a,c");
obj.Dump("2nd example", exclude: "+b,d"); // new in V5.06.06 beta

一个示例仅打印变量ac隐藏bd第二个示例相反(请注意,它仅指定两个可用参数)。变量yz不能单独隐藏,因为它们不在顶层。

以下参数可用(所有参数都是可选的):

  • description [string]-提供转储对象的描述
  • depth [int?]-限制递归检查对象的深度
  • toDataGrid [bool]-如果为true,则将输出格式化为datagrid而不是RichText
  • exclude[string]-如果您提供一个用逗号分隔的变量列表,则它们将从输出中排除(在示例“ a,c”中:bd被显示,a并且c被隐藏)
  • exclude带“ +”前缀的[string]-前缀反转exclude参数的逻辑。这意味着,如果您提供用逗号分隔的变量列表,则除指定变量外的所有变量都将被隐藏(在示例中,“ + b,d”:b并且d显示为已隐藏所有其他变量)
  • 将包含的属性和排除的属性存储在变量中(LinqPad V5.09.04之后的版本):
    var x=Util.ToExpando(obj, "a, c", "b, d"); x.Dump();
    第一个字符串包含要包含的属性的列表,第二个字符串包含要排除的列表
  • 点击展开:如果您使用.OnDemand("click me").Dump();而不是.Dump(),它将显示一个链接,您可以单击以展开。如果您想检查值,则很有用,例如Util.OnDemand("Customer-ID: " + customerObject.ID.ToString(), ()=>customerObject, false).Dump();始终显示默认值的ID,但customerObject仅在感兴趣时才显示详细信息。

可以在这里那里找到有关Dump的更多高级主题。


环境

这不是LinqPad扩展名,而是.NET类,但是由于它很有用,因此无论如何我都会提到它。您可以获得许多可以在脚本中使用的有用信息,例如:

Environment.UserDomainName.Dump();
Environment.MachineName.Dump();
Environment.UserName.Dump();
Environment.CurrentDirectory.Dump();
Environment.SystemDirectory.Dump();

注意:为了获得Domain\UserName我会使用 System.Security.Principal.WindowsIdentity.GetCurrent().Name
而不是Environment.UserDomainName+@"\"+Environment.UserName


实用程序

新功能:LinqPad版本v4.45.05(测试版开始)可用)

Util.WriteCsv (Customers, @"c:\temp\customers.csv");

这会将表的内容写入CustomersCSV文件c:\temp\customers.csv。您还可以Util.WriteCsv此处找到一个很好的示例,该示例如何使用并在Linqpad的结果窗口中显示CSV数据。

提示:

  • 要获取/创建与查询位于同一目录中的CSV文件,可以使用:
    var csvFile=Util.CurrentQueryPath.Replace(".linq", ".csv");

  • 如果表很大,请ObjectTrackingEnabled = false;在写入CSV之前使用以避免将其缓存在内存中。

  • 如果要以XML格式而不是以逗号分隔的文件形式输出表,可以执行以下操作:

    var xmlFile=Util.CurrentQueryPath.Replace(".linq", ".xml");
    var xml = XElement.Load(xmlFile);
    var query =
      from e in xml.Elements()
      where e.Attribute("attr1").Value == "a"
      select e;
    query.Dump();

    本示例返回具有属性的所有元素,该属性attr1包含"a"XML文件中的值,该XML文件的名称与查询名称相同,并且包含在同一路径中。查看链接以获取更多代码示例。


实用密码

var pwd = Util.GetPassword("UserXY");

这将从LinqPad的内置密码管理器中检索密码。要创建和更改密码,请在LinqPad 的“文件”菜单中打开“密码管理器”菜单项。如果在运行C#代码时没有保存密码,则会打开一个密码对话框,要求您输入密码,然后您可以通过选中“ 保存密码”复选框来动态创建和保存密码(例如,密码) “ UserXY”的名称将被保存,以后您可以在“ 密码管理器”中找到此条目)。

优点是,您可以将密码安全地,单独地存储在Windows创建的LinqScripts中,并在Windows的用户配置文件中加密(%localappdata%\LINQPad\Passwords以文件形式存储)。LinqPad使用Windows DPAPI保护密码。

另外,密码集中存储,因此,如果您需要更改密码,则可以在菜单中进行操作,并且密码会立即应用于您创建的所有脚本。

笔记:

  • 如果您不想保存密码而只想弹出一个密码对话框,则可以按如下所示使用第二个参数:
    var pwd = Util.GetPassword("UserXY", true);
    这将取消选中密码对话框中的“ 保存密码”复选框(但是,用户仍然可以对其进行检查并选择仍然保存)。

  • 如果您需要将密码存储在中SecureString,则可以使用此帮助器功能(nb:要使用扩展名方法.ToSecureString(),请在Stackoverflow上单击此链接 -如果需要,还可以将其转换回):
    System.Security.SecureString GetPasswordSecure(string Name, bool noDefaultSave=true)
    {
      return Util.GetPassword(Name, noDefaultSave).ToSecureString();
    }


实用程序命令

此方法的工作方式类似于命令处理器。您可以从Windows控制台调用所有已知的命令。

示例1-目录:

Util.Cmd(@"dir C:\");

这将输出目录的结果,而不需要.Dump它。将其存储在变量中的优点是可以在其上使用更多的Linq查询。例如:

var path=@"C:\windows\system32"; 
var dirSwitch="/s/b";
var x=Util.Cmd(String.Format(@"dir ""{0}"" {1}", path, dirSwitch), true);
var q=from d in x 
        where d.Contains(".exe") || d.Contains(".dll")              
        orderby d
    select d;
q.Dump();

这将转储包含的所有文件扩展名为“ .exe”或“ .dll”的文件C:\windows\system32。该/s开关用于递归所有子目录,/b并用于裸输出格式。请注意,指定Cmd方法的第二个参数以抑制控制台输出,以便仅显示使用Dump方法的过滤结果。

您可以看到,这比通配符更加灵活,dir因为您可以使用Linq的查询引擎的全部灵活性。

示例2-文本编辑器:

您可以像这样在记事本中打开文件:

var filePath=@"C:\HelloWorld.txt";
Util.Cmd(@"%systemroot%\system32\notepad.exe", filePath);

实用图片

显示来自URL的图像。例:

var url = "http://chart.apis.google.com/chart?cht=p3&chd=s:Uf9a&chs=350x140&chl=January|February|March|April";
Util.Image(url).Dump();

Util.ProgressBar,Util.Progress

使用Util.ProgressBar可以显示进度条。您可以使用以下帮助程序类:

public class ProgressBar
{
    Util.ProgressBar prog;

    public ProgressBar() 
    { 
        Init("Processing"); 
    }

    private void Init(string msg)
    {
        prog = new Util.ProgressBar (msg).Dump();
        prog.Percent=0;
    }

    public void Update(int percent)
    {
        Update(percent, null);
    }   

    public void Update(int percent, string msg)
    {
        prog.Percent=percent;
        if (String.IsNullOrEmpty(msg))
        {
            if (percent>99) prog.Caption="Done.";
        }
        else
        {
            prog.Caption=msg;
        }
    }
}

只需使用它,如以下示例所示:

void Main()
{
    var pb1= new ProgressBar();
    Thread.Sleep(50);
    pb1.Update(50, "Doing something"); Thread.Sleep(550);
    pb1.Update(100); Thread.Sleep(50);
}

您也可以使用Util.Progress来更新LinqPads集成进度条,例如:

Util.Progress = 25; // 25 percent complete

不同之处在于它不会显示在结果窗口中,并且您不能为其分配消息。


实用工具

在输出窗口中显示HTML。例:

Util.RawHtml (new XElement ("h1", "This is a big heading")).Dump();

Hyperlinq,Util.Horizo​​ntalRun

您可以使用此示例功能

public void ShowUrl(string strURL, string Title)
{
    Action showURL = delegate() { Process.Start("iexplore.exe", strURL); };
    var url = new Hyperlinq(showURL, "this link", true);
    Util.HorizontalRun (true, "Click ", url, " for details.").Dump(Title);
}

在结果窗口中显示超链接-或执行任何操作,例如打开您喜欢的编辑器。 用法:

ShowUrl("http://stackoverflow.com", "Check out StackOverflow");

请注意,此功能始终有效,new Hyperlinq ("http://myURL", "Web site").Dump();而不适用于某些类型的URL(特别是如果必须将诸如“:1234”之类的端口名作为URL的一部分传递的话)。


实用程序读取行

从控制台读取输入。例:

int age = Util.ReadLine<int> ("Enter your age");

作为的同义词Util.ReadLine<string>(),您也可以使用Console.ReadLine()

但是还有更多!您可以使用以下代码段创建一个简单的JSON解析器 -很有用,例如,如果您想动态地解析和测试JSON字符串。使用文本编辑器将以下代码段另存为JSONAnalyzer.linq,然后在LinqPad中将其打开(这是在运行时轻松添加引用):

<Query Kind="Program">
    <Reference>&lt;RuntimeDirectory&gt;\System.Web.Extensions.dll</Reference>
    <Namespace>System.Web.Script.Serialization</Namespace>
</Query>

void Main()
{
    var jsonData=Util.ReadLine<string>("Enter JSON string:");
    var jsonAsObject = new JavaScriptSerializer().Deserialize<object>(jsonData);
    jsonAsObject.Dump("Deserialized JSON");
}

现在,您可以运行它,只需将剪贴板中的JSON字符串粘贴到控制台中-它将使用该Dump函数将其很好地显示为对象-并且您还将在屏幕上获得解析器的错误消息以解决问题。对于调试AJAX非常有用。

JSON格式


Util.ClearResults

如果需要清除脚本中的结果窗口,请使用:

Util.ClearResults();

您可以在脚本顶部使用它,或者-如果您正在脚本中运行多个查询-您应该在黑屏之前等待用户输入(例如,在之前加上Util.ReadLine)。


自定义.Dump()-ICustomMemberProvider

同样有趣的是,您可以更改.Dump()方法的输出。只需实现接口即可ICustomMemberProvider,例如

public class test : ICustomMemberProvider 
{

      IEnumerable<string> ICustomMemberProvider.GetNames() {
        return new List<string>{"Hint", "constMember1", "constMember2", "myprop"};
      }

      IEnumerable<Type> ICustomMemberProvider.GetTypes() 
      {
        return new List<Type>{typeof(string), typeof(string[]), 
            typeof(string), typeof(string)};
      }

      IEnumerable<object> ICustomMemberProvider.GetValues() 
      {
        return new List<object>{
        "This class contains custom properties for .Dump()", 
        new string[]{"A", "B", "C"}, "blabla", abc};
      }

      public string abc = "Hello1"; // abc is shown as "myprop"
      public string xyz = "Hello2"; // xyz is entirely hidden
}

如果您创建此类的实例,例如

var obj1 = new test();
obj1.Dump("Test");

那么它会输出唯一的HintconstMember1constMember2,和myprop,但没有财产xyz

Linqpad转储


在LinqPad中显示MessageBox或InputBox

如果您需要显示一个消息框,请查看此处的操作方法。

例如,您可以使用以下代码显示一个InputBox

void Main()
{
    string inputValue="John Doe"; 
    inputValue=Interaction.InputBox("Enter user name", "Query", inputValue);
    if (!string.IsNullOrEmpty(inputValue)) // not cancelled and value entered
    {
        inputValue.Dump("You have entered;"); // either display it in results window
        Interaction.MsgBox(inputValue, MsgBoxStyle.OkOnly, "Result"); // or as MsgBox
    }
}

(不要忘记按F4并添加Microsoft.VisualBasic.dll及其命名空间以使此工作有效)


实用程序运行

新功能:LinqPad v4.52.1(测试版开始)可用)

允许您从脚本内或自己的.NET程序或Windows服务内运行另一个LINQPad脚本(通过引用的LINQPad4-AnyCPU版本LINQPad.exe)。它执行脚本的方式与命令行工具lprun.exe一样。

例子:

const string path=@"C:\myScripts\LinqPad\";
var dummy=new LINQPad.QueryResultFormat(); // needed to call Util.Run
Util.Run(path+"foo.linq", dummy);

本示例运行脚本foo.linq,其中包含以下示例代码:

void Main(string[] args)
{
    #if CMD
       "I'm been called from lprun! (command line)".Dump();
    #else
       "I'm running in the LINQPad GUI!".Dump();
       args = new[] { "testhost", "test@foo.com", "test@foo.com", "Test Subject" };
    #endif
    args.Dump("Args");
}

它允许您检查脚本是从LinqPad GUI内部运行还是通过lprun.exe或与一起运行Util.Run

注意:下列变种的调用可能会有所帮助:

Util.Run(path+"foo.linq", dummy).Dump(); // obviously dumps the script output!
Util.Run(path+"foo.linq", dummy).Save(path+"foo.log"); // writes output into log
Util.Run(path+"foo.linq", dummy).SaveAsync(path+"foo1.log");     // async output log

SubmitChanges()-Linq转SQL

如果您使用LinqToSQL,则可能要使更改永久化(用于插入/更新/删除操作)。由于数据库上下文是由LinqPad隐式创建的,因此您需要SubmitChanges()在每次更改后调用 ,如下所示。

(LinqPad-)Northwind数据库的示例:

var newP = new Products() { ProductID=pID, CategoryID=cID, 
            ProductName="Salmon#"+pID.ToString() };
Products.InsertOnSubmit(newP);
SubmitChanges();    

更新资料

var prod=(from p in Products
            where p.ProductName.Contains("Salmon")
            select p).FirstOrDefault();
prod.ProductName="Trout#"+prod.ProductID.ToString();
SubmitChanges(); 

删除

var itemsToDelete=Products.Where(p=> p.ProductName.Contains("Salmon") ||
    p.ProductName.Contains("Trout"));
foreach(var item in itemsToDelete) { Products.DeleteOnSubmit(item); }
SubmitChanges();

注意:为了获得前面示例的有效ID,可以使用:

var cID = (from c in Categories 
            where c.CategoryName.Contains("Seafood") 
            select c).FirstOrDefault().CategoryID;

var pID = Products.Count()+1;

在调用它们之前。


SaveChanges()-实体框架

如果您使用的是Entity Framework,则可能还希望使更改永久生效(用于插入/更新/删除操作)。由于数据库上下文是由LinqPad隐式创建的,因此您需要SaveChanges()在每次更改后调用 ,如下所示。

这些示例基本上与以前的LinqToSQL相同,但是您需要使用这些示例SaveChanges(),并且插入和删除方法也已更改。

var newP = new Products() { ProductID=pID, CategoryID=cID, 
            ProductName="Salmon#"+pID.ToString() };
Products.Add(newP);
SaveChanges();  

更新资料

var prod=(from p in Products
            where p.ProductName.Contains("Salmon")
            select p).FirstOrDefault();
prod.ProductName="Trout#"+prod.ProductID.ToString();
SaveChanges(); 

删除

var itemsToDelete=Products.Where(p=> p.ProductName.Contains("Salmon") ||
    p.ProductName.Contains("Trout"));
foreach(var item in itemsToDelete) { Products.Remove(item); }
SaveChanges();

注意:为了获得前面示例的有效ID,可以使用:

var cID = (from c in Categories 
            where c.CategoryName.Contains("Seafood") 
            select c).FirstOrDefault().CategoryID;

var pID = Products.Count()+1;

在调用它们之前。


这-数据库上下文

LinqPad中,通过使用顶部的组合框并为您的查询选择合适的数据库来自动应用数据库上下文。但是有时,明确引用它很有用,例如,如果您从Visual Studio中复制项目中的某些代码,然后将其粘贴到LinqPad中。

您从Visual Studio项目中摘录的代码片段很可能像这样:

var prod=(from p in dc.Products
            where p.ProductName.Contains("Salmon")
            select p).FirstOrDefault();
prod.ProductName="Trout#"+prod.ProductID.ToString();
dc.SaveChanges(); 

现在该怎么办dc?当然,您可以删除dc.查询中的每个匹配项,但这要容易得多。只需添加

var dc=this; // UserQuery

如下所示:

void Main()
{
    var dc=this;
    var prod=(from p in dc.Products
                where p.ProductName.Contains("Salmon")
                select p).FirstOrDefault();
    prod.ProductName="Trout#"+prod.ProductID.ToString();
    dc.SaveChanges(); 
}   

代码将立即生效!


this.Connection

将LinqPad与OleDb结合使用,将数据表转换为Linq对象,并在Linq中进行SQL查询

以下代码段可帮助您将LinqPad与OleDb结合使用。System.Data.OleDbSystem.Data程序集添加到查询属性,然后将以下代码粘贴到Main()

var connStr="Provider=SQLOLEDB.1;"+this.Connection.ConnectionString; 

OleDbConnection conn = new OleDbConnection(connStr);
DataSet myDS = new DataSet();
conn.Open();

string sql = @"SELECT * from Customers";
OleDbDataAdapter adpt = new OleDbDataAdapter();
adpt.SelectCommand = new OleDbCommand(sql, conn); 
adpt.Fill(myDS);

myDS.Dump();

现在,将一个SqlServer连接添加到LinqPad并添加Northwind数据库以运行此示例。

注意:如果只想获取当前选定连接的数据库和服务器,则可以使用以下代码片段:

void Main()
{
    var dc=this;
    var tgtSrv=dc.Connection.DataSource;
    var tgtDb=dc.Connection.ConnectionString.Split(';').Select(s=>s.Trim())
        .Where(x=>x.StartsWith("initial catalog", StringComparison.InvariantCultureIgnoreCase))
        .ToArray()[0].Split('=')[1];
    tgtSrv.Dump();
    tgtDb.Dump();
}

您甚至可以转换myDSLinq,以下问题的答案显示了如何做到这一点:在Linq中使用.NET 4动态关键字的好例子

再举一个例子:假设您的DBA给您一个SQL查询,并且您想在LinqPad中分析结果-当然是在Linq中,而不是在SQL中。然后,您可以执行以下操作:

void Main()
{
    var dc=this;

    // do the SQL query
    var cmd =
        "SELECT Orders.OrderID, Orders.CustomerID, Customers.CompanyName,"
        +"       Customers.Address, Customers.City"
        +" FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID";
    var results = dc.ExecuteQuery<OrderResult>(cmd);

    // just get the cities back, ordered ascending
    results.Select(x=>x.City).Distinct().OrderBy(x=>x).Dump();
}

class OrderResult
{   // put here all the fields you're returning from the SELECT
    public dynamic OrderID=null; 
    public dynamic CustomerID=null;
    public dynamic CompanyName=null;
    public dynamic Address=null;
    public dynamic City=null;
}

在此示例中,仅将DBA的SELECT查询“抛入”命令文本中,然后按City过滤和排序结果。
当然,这是一个简化的示例,您的DBA可能会给您一个更复杂的脚本,但是您已经明白了:只需添加一个支持结果类,其中包含SELECT子句中的所有字段,然后就可以直接使用它。
您甚至可以通过这种方式从存储过程中获取结果,并在Linq中使用它。如您所见,在此示例中,我不在乎数据类型并使用dynamic它来表示它。
因此,这实际上是关于快速编程以便能够快速分析数据。出于各种原因(SQL注入,因为从一开始就可以使用EF),您不应在实际的应用程序中执行此操作。


面板管理器

在LinqPad中绘制图形,第1部分

使用下面的例子中,按F4添加System.Windows.dllSystem.Windows.Forms.dllWindowsFormsIntegration.dllPresentationCore.dllPresentationFramework.dll你的LinqPad程序,并添加命名空间System.Windows.Shapes

一个示例只是画一条线:

var myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = 1; myLine.X2 = 50;
myLine.Y1 = 1; myLine.Y2 = 50;
myLine.StrokeThickness = 2;
PanelManager.DisplayWpfElement(myLine, "Graphic");

第二个例子展示了如何通过使用PanelManager显示LinqPad图形。通常,LinqPad仅支持Wpf对象。本例中使用System.Windows.Forms.Integration.WindowsFormsHost,以使Windows.Forms.PictureBox可用的(它的灵感来自于这个):

// needs (F4): System.Windows.dll, System.Windows.Forms.dll, 
// WindowsFormsIntegration.dll, PresentationCore.dll, PresentationFramework.dll 
void Main()
{       
    var wfHost1 = new System.Windows.Forms.Integration.WindowsFormsHost();
    wfHost1.Height=175; wfHost1.Width=175; wfHost1.Name="Picturebox1";
    wfHost1.HorizontalAlignment=System.Windows.HorizontalAlignment.Left;
    wfHost1.VerticalAlignment=System.Windows.VerticalAlignment.Top;
    System.Windows.Forms.PictureBox pBox1 = new System.Windows.Forms.PictureBox();
    wfHost1.Child = pBox1;
    pBox1.Paint += new System.Windows.Forms.PaintEventHandler(picturebox1_Paint);
    PanelManager.StackWpfElement(wfHost1, "Picture");
} 

public string pathImg
{
    get { return System.IO.Path.Combine(@"C:\Users\Public\Pictures\Sample Pictures\", 
            "Tulips.jpg"); } 
}

// Define other methods and classes here
public void picturebox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    // https://stackoverflow.com/a/14143574/1016343
    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(pathImg);
    System.Drawing.Point ulPoint = new System.Drawing.Point(0, 0);
    e.Graphics.DrawImage(bmp, ulPoint.X, ulPoint.Y, 175, 175);
}

这将创建以下图形(上面的示例添加了面板项目“ Graphic”和“ Picture”):

正在显示_图形_in_LinqPad

如果要显示Northwind数据库中的图像,可以执行以下操作:
将图像文件名更改为“ NorthwindPics.jpg”,然后在第二个示例的 Main()方法的开头添加以下代码:

var img = (from e in this.Employees select e).FirstOrDefault().Photo.ToArray();
using (FileStream fs1 = new FileStream(pathImg, FileMode.Create))
{
    const int offset=78;
    fs1.Write(img, offset, img.Length-offset);
    fs1.Close();
}

它将从雇员表中读取第一条记录并显示图片。

查看以下链接以了解更多信息:
WPF LinqPad自定义可视化工具中的形状和基本工程图

注意:也可以在没有PanelManager的情况下实现相同的功能,如下面的示例所示(在这里看到):

// using System.Drawing;
using (var image=new Bitmap(100, 100))
using (var gr = Graphics.FromImage(image))
{
    gr.FillRectangle(Brushes.Gold, 0, 0, 100, 100);
    gr.DrawEllipse(Pens.Blue, 5, 5, 90, 90);
    gr.Save();
    image.Dump();
}

它正在使用.Dump()命令显示它。您可以调用image.Dump()多次,它将附加图像。


Windows表格

在LinqPad中绘制图形,第2部分

以下示例受本文的启发,显示了如何使用C#7在Linqpad 5中实现一个简单的函数绘图仪:

void Main()
{
    fnPlotter(x1: -1, x2: 1, fn: (double x) => Math.Pow(x, 3)).Dump();
}

public static Bitmap fnPlotter(double x1=-3, double x2=3, double s=0.05, 
                                   double? ymin=null, double? ymax=null, 
                                   Func<double, double> fn = null, bool enable3D=true)
{
    ymin = ymin ?? x1; ymax = ymax ?? x2;

    dynamic fArrPair(double p_x1 = -3, double p_x2 = 3, double p_s = 0.01, 
                          Func<double, double> p_fn = null)
    {
        if (p_fn == null) p_fn = ((xf) => { return xf; }); // identity as default
        var xl = new List<double>(); var yl = new List<double>();
        for (var x = p_x1; x <= p_x2; x += p_s)
        {
            double? f = null;
            try { f = p_fn(x); }
            finally
            {
                if (f.HasValue) { xl.Add(x); yl.Add(f.Value); }
            }
        }
        return new { Xs = xl.ToArray(), Ys = yl.ToArray() };
    }

    var chrt = new Chart(); var ca = new ChartArea(); chrt.ChartAreas.Add(ca);
    ca.Area3DStyle.Enable3D = enable3D;
    ca.AxisX.Minimum = x1; ca.AxisX.Maximum = x2;   
    ca.AxisY.Minimum = ymin.Value; ca.AxisY.Maximum = ymax.Value;

    var sr = new Series(); chrt.Series.Add(sr);
    sr.ChartType = SeriesChartType.Spline; sr.Color = Color.Red;
    sr.MarkerColor = Color.Blue; sr.MarkerStyle = MarkerStyle.Circle;
    sr.MarkerSize = 2;

    var data = fArrPair(x1, x2, s, fn); sr.Points.DataBindXY(data.Xs, data.Ys); 
    var bm = new Bitmap(width: chrt.Width, height: chrt.Height);
    chrt.DrawToBitmap(bm, chrt.Bounds); return bm;
}

它使用LinqPad的功能在结果面板中显示Windows表单。 添加引用(新闻:,,并从这些组件添加所有的命名空间。
例
F4
System.Drawing.dllSystem.Windows.Forms.dllSystem.Windows.Forms.DataVisualization.dll


其他提示/进一步阅读:

  • 是否要在Visual Studio中使用LinqPad ?这是您可以执行的操作

  • 是否需要LinqPad作为“便携式应用程序”在这里阅读如何做。

  • Joe的LinqPad网站始终是一个很好的来源。在LinqPad内部,Help -> What's New可为您提供有关新功能和方法的提示。该LinqPad论坛还包含有用的提示。

  • 也非常有帮助:文章有关的LINQ(PAD)的调试。

  • 使用lprun.exe用于运行LINQ查询您的批处理脚本。阅读本文以获取更多详细信息。例如:
    echo Customers.Take(100) > script.txt
    lprun -lang=e -cxname=CompanyServer.CustomerDb script.txt
    在此示例中,查询是一个简单的LINQ表达式。当然,您也可以使用-lang=program激活程序模式来准备复杂的查询。

  • 您可以编写扩展方法并将其存储在LinqPad左侧的“ 我的查询”选项卡中:树的最后一项名为“ 我的扩展”;双击它可以打开一个文件,您可以在其中编写所有查询可用的扩展名。只需将它们放入public static class中MyExtensions,并使用该Main()方法包括扩展的测试。


2
喜欢有关Util.ReadLine <string>(“输入一些json”)的提示;以前我曾经将其复制到文件中,然后从那里读取...我真的很喜欢这个技巧。谢谢!
loneshark99

2

转储是全局扩展方法,SubmitChanges来自DataContext对象,该对象是System.Data.Linq.DataContext对象。

据我所知,LP仅添加了“转储”和“反汇编”。尽管我强烈建议在Reflector中打开它,看看还有什么可以使用的。更加有趣的事情之一是LINQPad.Util命名空间,它具有LINQPad内部使用的一些优点。


注意:在较新版本的LinqPad中:单击.Dump()源编辑器中的或任何其他方法,按F12 以“反射”。现在,该工具已内置!
马特

1

在我之前的回答中达到了StackOverflow文本限制,但是LinqPad中仍然有更多很棒的扩展。我想提及其中之一:


JavaScript函数(使用.Dump()

从LinqPad的5.42 beta版开始,您可以嵌入JavaScript函数并直接从C#代码中调用它们。尽管它有一些限制(与JSFiddle相比),但是它是在LinqPad中快速测试某些JavaScript代码的好方法。

例:

void Main()
{
    // JavaScript inside C#
    var literal = new LINQPad.Controls.Literal("script",
    @"function jsFoo(x) { 
        alert('jsFoo got parameter: ' + x); 
        var a = ['x', 'y', 'z']; external.log('Fetched \'' + a.pop() + '\' from Stack');
        external.log('message from C#: \'' + x + '\''); 
    }"); 
    // render & invoke
    literal.Dump().HtmlElement.InvokeScript(true, "jsFoo", "testparam");
}

在此示例中,jsFoo准备了具有一个参数的函数并将其存储在变量中literal。然后,通过.Dump().HtmlElement.InvokeScript(...)传递参数渲染并调用它testparam

JavaScript函数用于external.Log(...)在LinqPad的输出窗口中输出文本,并alert(...)显示弹出消息。

您可以通过添加以下扩展类/方法来简化此操作:

public static class ScriptExtension
{
    public static object RunJavaScript(this LINQPad.Controls.Literal literal, 
                                       string jsFunction, params object[] p)
    {
        return literal.Dump().HtmlElement.InvokeScript(true, jsFunction, p);
    }
    
    public static LINQPad.Controls.Literal CreateJavaScript(string jsFunction)
    {
        return new LINQPad.Controls.Literal("script", jsFunction);
    }
}

然后,您可以按以下方式调用上一个示例:

    // JavaScript inside C#
    var literal = ScriptExtension.CreateJavaScript(
    @"function jsFoo(x) { 
        alert('jsFoo got parameter: ' + x); 
        var a = ['x', 'y', 'z']; external.log('Fetched \'' + a.pop() + '\' from Stack');
        external.log('message from C#: \'' + x + '\''); 
    }"); 

    // render & invoke
    literal.RunJavaScript("jsFoo", "testparam");

这具有相同的效果,但更易于阅读(如果您打算使用更多JavaScript ;-))。

另一个选择是,如果您喜欢Lambda表达式,并且不想每次调用时都将函数名指定为字符串,则可以执行以下操作:

var jsFoo = ScriptExtension.CreateJavaScript(
            @"function jsFoo(x) { ...  }"); 
ScriptExtension.RunJavaScript(() => jsFoo, "testparam");

前提是您已经添加了辅助功能

public static object RunJavaScript(Expression<Func<LINQPad.Controls.Literal>> expr,  
                                   params object[] p)
{
    LINQPad.Controls.Literal exprValue = expr.Compile()();
    string jsFunction = ((MemberExpression)expr.Body).Member.Name;
    return exprValue.Dump().HtmlElement.InvokeScript(true, jsFunction, p);
}

上课ScriptExtension。这将解析您使用的变量名(此处为jsFoo),该名称恰好与JavaScript函数本身相同(请注意,如何使用lambda表达式解析变量名,这不能通过nameof(paramName)在函数内部使用来完成)。


.Dump()-内联更新消息

有时,覆盖转储的文本而不是将其放在新行中很有用,例如,如果您正在执行长时间运行的查询并希望显示其进度等(另请参见下面的ProgressBar)。可以使用来完成此操作DumpContainer,您可以按所示使用它

范例1:

void Main()
{
   var dc = new DumpContainer("Doing something ... ").Dump("Some Action");
   System.Threading.Thread.Sleep(3000); // wait 3 seconds
   dc.Content += "Done.";
}

DumpContainerAnimation

请注意,对于某些更复杂的对象,您可能必须使用dc.UpdateContent(obj);而不是dc.Content=...

范例2:

void Main()
{
    var dc = new DumpContainer().Dump("Some Action");
    for (int i = 10; i >= 0; i--)
    {
        dc.UpdateContent($"Countdown: {i}");
        System.Threading.Thread.Sleep(250);
    };
    dc.UpdateContent("Ready for take off!");
}

实用程序进度条

也可以通过使用ProgressBar来显示进度,如下所示:

例:

void Main()
{
    var prog = new Util.ProgressBar("Processing").Dump();
    for (int i = 0; i < 101; i++)
    {
       Thread.Sleep(50); prog.Percent = i;
    }
    prog.Caption = "Done";
}

这类似于之前的转储示例,但是这次显示了一个不错的进度条动画。


使用LinqPad进行单元测试-xUnit

您知道可以在LinqPad中编写单元测试吗?例如,您可以使用xUnit框架。可通过LinqPad的NUGET支持(通过F4-单击对话框中的)获得Add NUGET....。这是逐步说明如何将 xUnit与LinqPad V5或V6一起使用。


如果有更多发现,我将更新此答案

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.