LINQPad [扩展] 方法 [关闭]

Posted

技术标签:

【中文标题】LINQPad [扩展] 方法 [关闭]【英文标题】:LINQPad [extension] methods [closed] 【发布时间】:2011-04-03 02:08:45 【问题描述】:

有没有人有完整的LINQPad扩展方法和方法列表,比如

.Dump()

SubmitChanges()

【问题讨论】:

我投票结束这个问题,因为 LINQPad 是一个不断变化的工具,对这个问题有一个坚实而具体的和 final 答案将有一个生命很短暂。我建议将其作为离题关闭,以避免向其他工具推广类似问题。 并不是说我对投票有什么要说的,但我当然不同意关闭这个答案。首先,只需查看该问题的投票数,然后查看前两个 cmets 的投票数。第二,约瑟夫的答案怎么可能不是最终的答案?他写的东西。最后,其他应用程序使用 *** 作为其文档。我一直使用 LinqPad 进行开发、制作 C# 和 Linq 查询原型、运行 SQL、执行 Quick DBA 任务以及其他许多事情。所以,至少对我来说,答案肯定是主题。 重新结束:我已经为 C# 上的旧问题添加了多个答案,以提供一种更现代的技术,自问题得到解答以来,该技术已被引入该语言。 IMO 我们应该期望这个站点所代表的知识库随着技术的发展而被修改和更新。未来更新可能会影响或取消在特定时间点给出的答案的主题范围非常广泛:如果我们关闭所有可能发生这种情况的问题,Stack Overflow 将是一个更糟糕的资源!在这里,一个完整的列表可能会变成一个部分列表,这比没有列表要好! 这里不应该讨论这个。把它带到Meta Stack Overflow。 @Samuel Liew:我不同意关闭这个问题:如果您要关闭这个问题,那么您需要关闭所有其他涉及 Microsoft 产品的问题,例如 Visual Studio, SQL Server、Azure 等,并删除它们的标签——因为这也指的是软件。 【参考方案1】:

第 2 部分,共 2 部分

Go to part 1


在我的previous answer 中达到了 *** 文本限制 30000 个字符,但在 LinqPad 中还有更酷的扩展。其中一些我想提一下:


在 LinqPad 中编写自己的扩展

列表表

您是否知道您可以在 LinqPad 中编写自己的扩展,并在所有查询中都可用? 以下是您的操作方法: 在 LinqPad 中,转到左侧的“我的查询”选项卡,向下滚动到最后,直到看到“我的扩展”。双击它,它将打开一个名为 My Extensions 的特殊查询窗口。您在那里写的内容将在所有查询中可用。

现在把下面的代码粘贴进去,然后用Ctrl+S保存:

我的扩展

void Main()

    // no code here, but Main() must exist


public static class MyExtensions

    /// <summary>
    /// This will list the tables of the connected database
    /// </summary>
    public static void ListTables(this System.Data.Linq.DataContext dc)
    
        var query = dc.Mapping.GetTables();
        query.Select(t => t.TableName).OrderBy(o => o).Dump();
    

Joe(LinqPad 的作者)好心地为我提供了这个 sn-p - 它展示了如何将数据上下文传递给 My Extensions。

通过以下方式使用此扩展:在 LinqPad 中打开一个新的 C# 查询窗口(使用 Ctrl+N),然后连接到您选择的数据库,然后键入:

新查询

void Main()

    this.ListTables();

重要提示:如果您没有连接到数据库,则扩展程序不可用,LinqPad 将显示错误。所以,先连接数据库,然后输入this.ListTables();

请注意,IntelliSense 将显示我们在“我的扩展”中键入的 XML 注释的摘要。一旦你运行它,你会得到一个当前数据库的表列表。


LinqPad 中的配置文件 (appsettings.json)


之前我已经展示了如何使用 MyExtensions。现在,如果您想要一个全局 appsettings.json 文件或每个脚本一个,您可以使用以下扩展名:

public static class MyExtensions

    // needs: Microsoft.Extensions.Configuration.json, press F4 and add it as NUGET package
    public static IConfiguration AppSettings(string path = null)
    
            IConfiguration config = null;
            var configFile = (path != null) ? path : Util.CurrentQueryPath.Replace(".linq", ".appsettings.json");
            if (System.IO.File.Exists(configFile))
            
                var builder = new ConfigurationBuilder().AddJsonFile(configFile);
                config = builder.Build();
            
            else
            
                configFile.Dump("Not found");
            
            return config;
    

您也可以将其直接存储在您的 C# 程序中,但这种方式默认情况下是可用的,您只需加载一次 NUGET。

假设你编写了一个 LinqPad 程序"YourCSharpProgram.linq"。 现在您可以提供类似的配置

var config1 = MyExtensions.AppSettings();

或喜欢

var config2 = MyExtensions.AppSettings("C:\MyGlobalSettings\appsettings.json");

第一个选项 config1 将期望文件"YourCSharpProgram.linq" 下的设置并将"appsettings.json" 附加到它,这意味着您的设置必须位于与程序相同的文件夹中的"YourCSharpProgram.linq.appsettings.json" 中。 第二个选项只是使用指定的绝对路径。

如果您的设置文件包含


    "AzureStorage": 
        "StorageConnectionString": "some connection string"
    

你可以像这样访问它

var config = MyExtensions.AppSettings();
string connectionString = config.GetSection("AzureStorage").GetSection("StorageConnectionString").Value.ToString();
connectionString.Dump();

注意:第二种使用配置的方法是将 JSON 文件的绝对路径放在 LinqPads F4 对话框中。在 LinqPad 5 中,这更好,因为设置文件有一个单独的选项卡(那里是 AppConfig,因为版本 5 用于 .NET,而不是用于 .NET 核心)。您必须像使用程序集一样引用它,这并不明显。所以我更喜欢上面描述的。

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) 来完成函数)。


使用 LinqPad - xUnit 进行单元测试

您知道您可以在 LinqPad 中编写单元测试吗?例如,您可以使用 xUnit 框架。对于 LinqPad 版本 5,可通过 LinqPad 的 NUGET 支持 - 通过 F4 - 在对话框中单击 Add NUGET....。从 LinqPad 版本 6 开始,它是内置的(菜单查询 -> 添加 XUnit 测试支持)。这里是一步一步的描述如何 use xUnit with LinqPad V5, V6 or V7.


.Dump() - 更新内联消息

有时,覆盖您转储的文本而不是将其放入新行中很有用,例如,如果您正在执行长时间运行的查询并希望显示其进度等(请参阅下面还有进度条)。这可以通过使用DumpContainer 来完成,您可以使用它,如

示例 1:

void Main()

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

注意,对于一些更复杂的对象,您可能必须使用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!");


Util.ProgressBar

也可以使用 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";

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


为您的转储着色 - Util.HighlightIf

您可以使用Util.HighlightIf(condition, object)Util.HighlightIf(condition, htmlcolor, object) 创建彩色转储。

以下示例取自 LinqPad 的发行说明,并对其进行了更多着色:

void Main()

    (from file in new DirectoryInfo(Util.LINQPadFolder).GetFiles()
    select 
        Util.HighlightIf(file.Extension == ".txt", "lightblue",
        Util.HighlightIf(file.Extension == ".json" || file.Extension == ".xml", "lightcyan",
        Util.HighlightIf(file.Extension == ".cmd" || file.Extension == ".bat", "lightyellow",
        Util.HighlightIf(file.Extension == ".dll", "lightgreen",  
        Util.HighlightIf(file.Extension == ".exe",    // Highlight the entire row if the file is an executable.
                         new file.Name, 
                              Length=Util.HighlightIf(file.Length>999999,"orange",file.Length) ,
                              LastWriteDate=DateTime.Today.Date.ToString("yyyy-MM-dd")
        )))))).Dump();

现在,它有什么作用? 它根据颜色为单元格着色

文件扩展名。文件扩展名.bat.txt.json.cmd.dll.xml.exe 分别具有不同的颜色(有些共享相同的颜色)。 文件大小。如果大小超过999999 bytes,则其单元格将显示为橙色。

这将创建一个像这样的转储:


多数据库支持

LinqPad (LinqPad 6 Premium) 的付费版本支持一个查询中的多个数据库。

下面我将描述选择“Linq to SQL (Optimized for SQL Server)”时获得的数据库属性的步骤。

要么创建一个新的连接,要么打开一个现有的连接。打开Database Properties,选择一个数据库(不要使用“Display all in a TreeView)

然后勾选“包括其他数据库” - 这将打开另一个对话框,您可以在其中添加多个数据库:

单击从列表中选择...,您可以选择+选择另一个数据库。完成后,单击 Close 关闭附加对话框,然后单击 Ok 关闭数据库属性。

选择的数据库有“次要”上下文(在“this”UserQuery 中与数据库名称一起列出),第一个数据库(您在“指定新数据库或现有数据库”下选择)是“主要”上下文(这意味着,表直接出现在“this”UserQuery 中)。

在连接窗口中,这将显示为

".\MyInstance\AdventureWorks2017 + AdventureWorks2017 + Northwind"


在下面的代码中,我使用“AdventureWorks2017”作为主要上下文,使用“AdventureWorks2017”和“Northwind”作为次要上下文。

这样准备,你可以这样做:

public UserQuery ctx => this; // context
void Main()

 // "primary database"
 ctx.Products.Select(s => new s.ProductID, Name=s.Name).Take(3).Dump("AdventureWorks");

 // "secondary" databases
 var aw = ctx.AdventureWorks2017;
 var nw = ctx.Northwind;

 nw.Products.Select(s => new s.ProductID, Name=s.ProductName).Take(3).Dump("Northwind");
 aw.Products.Select(s => new s.ProductID, Name=s.Name).Take(3).Dump("AdventureWorks");

此示例中使用的两个示例数据库都来自 Microsoft,可以免费下载,它们都有一个 Products 表,但具有不同的属性/字段:您可以看到我已重命名 ProductName / Name 所以它在所有查询中显示为 Name。

程序会给你结果:

下载链接: AdventureWorks、Northwind、LinqPad


如果我发现更多,我会不时更新这个答案

【讨论】:

【参考方案2】:

第 1 部分,共 2 部分


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

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

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

为了总结,我将向您展示如何在 LinqPad 中创建简单的 2d 图形(绘制线条、位图函数)。

所以,这里有一组内置 LinqPad 功能(根据我自己使用该工具的经验):


.Dump()

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

.Dump() 扩展方法消耗并打印(几乎)所有内容。

但是您知道有几个参数可用吗? 看看这段代码sn-p:

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第二个例子做相反的事情(注意它仅指定 2 个可用参数)。变量yz 不能单独隐藏,因为它们不在顶层。

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

description [string] - 为要转储的对象提供描述 depth [int?] - 限制递归检查对象的深度 toDataGrid [bool] - 如果为真,则输出格式为数据网格而不是 RichText exclude [string] - 如果您提供以逗号分隔的变量列表,它们将从输出中排除(在示例中“a,c”:bd 显示,a 和 @ 987654370@ 已隐藏) exclude [string] 带有“+”前缀 - 前缀反转了 exclude 参数的逻辑。这意味着,如果您提供以逗号分隔的变量列表,则除了指定的变量之外的所有变量都被隐藏(在示例中“+b,d”:bd 显示,所有其他变量都隐藏) 将包含和排除的属性存储在变量中(自 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(), ()=&gt;customerObject, false).Dump(); 始终默认显示 ID,但仅在您感兴趣时才显示 customerObject 的详细信息。

更多关于 Dump 的高级主题可以在 here 和 there 找到。


环境

这不是一个 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


Util.WriteCsv

新:自LinqPad version v4.45.05 (beta)起可用)

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

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

提示:

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

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

如果你想以 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();

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


Util.GetPassword

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

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

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

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

注意事项:

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

如果您需要将密码存储在SecureString 中,您可以使用此帮助函数(nb:获取使用的扩展方法.ToSecureString(),请关注this link at *** - 它还允许您将其转换回来如果需要):System.Security.SecureString GetPasswordSecure(string Name, bool noDefaultSave=true) return Util.GetPassword(Name, noDefaultSave).ToSecureString();


Util.Cmd

此方法的工作原理类似于命令处理器。您可以从 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();

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

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

示例 2 - 文本编辑器:

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

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

Util.Image

显示来自 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

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


Util.RawHtml

在输出窗口中显示 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://***.com", "Check out ***");

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


Util.ReadLine

从控制台读取输入。示例:

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

作为Util.ReadLine&lt;string&gt;() 的同义词,您也可以使用Console.ReadLine()

但还有更多!您可以使用以下 sn-p 创建一个简单的 JSON 解析器 - 非常有用,例如,如果您想即时解析和测试 JSON 字符串。 使用文本编辑器将以下 sn-p 保存为 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 非常有用。


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");

那么它将只输出HintconstMember1constMember2myprop,而不是属性xyz


在 LinqPad 中显示 MessageBox 或 InputBox

如果你需要显示一个消息框,看here怎么做。

例如,您可以使用以下代码显示一个 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 及其命名空间以使其工作)


Util.Run

新:自LinqPad version v4.52.1 (beta)起可用)

允许您从您的脚本或您自己的 .NET 程序或 Windows 服务中运行另一个 LINQPad 脚本(通过引用LINQPad.exe 的 LINQPad4-AnyCPU 版本)。它像命令行工具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.exeUtil.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 To SQL

如果您使用的是 LinqToSQL,您可能希望永久更改(对于 insert/update/delete 操作)。 由于数据库上下文是由 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,您可能还希望永久更改(对于 insert/update/delete 操作)。 由于数据库上下文是由 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;

在调用它们之前。


this - 数据库上下文

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

您从 Visual Studio 项目中获取的代码 sn-p 很可能如下所示:

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.,但这要容易得多。 只需将它添加到您的 sn-p 顶部,如下所示:

UserQuery dc  get => this; 
void Main()

    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 查询

以下代码 sn-p 帮助您将 LinqPad 与 OleDb 一起使用。将System.Data 程序集中的System.Data.OleDb 添加到查询属性中,然后将以下代码粘贴到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();

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

注意:如果只是想获取当前选中连接的数据库和服务器,可以使用这段代码sn -p:

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();

您甚至可以将myDS 转换为Linq,以下问题的答案显示了如何做到这一点:Nice examples of using .NET 4 dynamic keyword with Linq

再举一个例子:假设您的 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 查询只是“投入”命令文本,结果按城市过滤和排序。 当然,这是一个简化的示例,您的 DBA 可能会给您一个更复杂的脚本,但您的想法是:添加一个包含 SELECT 子句中所有字段的支持结果类,然后您可以直接使用它。 您甚至可以通过这种方式从存储过程中获取结果并在 Linq 中使用它。可以看到,在这个例子中我不关心数据类型,使用dynamic来表达。 所以这实际上是关于快速编程以便能够快速分析数据。由于各种原因(SQL 注入,因为您可以从一开始就使用 EF 等),您不应该在实际应用程序中执行此操作。


面板管理器

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

要使用下面的示例,请按 F4 并将 System.Windows.dllSystem.Windows.Forms.dllWindowsFormsIntegration.dllPresentationCore.dllPresentationFramework.dll 添加到您的 LinqPad 程序中,并添加命名空间 @987654473 @。

第一个例子简单地画了一条线:

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 使PictureBox 可用(它的灵感来自this):

// 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://***.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);

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

如果您想显示 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();

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

查看以下链接以了解更多信息:Shapes and basic drawing in WPF LinqPad custom visualizers

注意:您也可以在没有 PanelManager 的情况下实现相同的效果,如下例所示,我看到 here 显示:

// 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 部分

以下示例受 this 帖子的启发,展示了如何使用 C#7 在 Linqpad 中实现函数绘图仪:

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 表单。 添加引用(按 F4System.Drawing.dllSystem.Windows.Forms.dllSystem.Windows.Forms.DataVisualization.dll并从这些程序集中添加所有命名空间。


其他提示/进一步阅读:

想在 Visual Studio 中使用 LinqPad?这是how you can do that。

需要将 LinqPad 作为“便携式应用程序”? Read here 怎么做。

Joe 的LinqPad 网站是一个很好的来源。在 LinqPad 中,Help -&gt; What's New 为您提供有关新功能和方法的提示。 LinqPad Forum 还包含有用的提示。

也有帮助:This 有关 Linq(Pad) 调试的文章。

使用 lprun.exe 在您的批处理脚本中运行 LINQ 查询阅读this article 了解更多详情。 例如:echo Customers.Take(100) &gt; script.txt lprun -lang=e -cxname=CompanyServer.CustomerDb script.txt 在此示例中,查询是一个简单的 LINQ 表达式。当然,你也可以准备复杂的查询,使用-lang=program激活程序模式。

您可以在 LinqPad 左侧的 My Queries 选项卡中编写和存储扩展方法:树的最后一项名为 My Extensions;双击它打开一个文件,您可以在其中编写可用于所有查询的扩展名。将它们放入公共静态类MyExtensions,并使用Main() 方法包含扩展测试。


Continued here...

【讨论】:

喜欢关于 Util.ReadLine ("Enter some json") 的提示;早些时候我曾经将它复制到文件中,然后从那里读取......我真的很喜欢这个技巧。谢谢! 神圣的。地狱。此处记录的最佳答案之一。谢谢!!【参考方案3】:

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 - 返回代表您保存的查询/样本的对象集合(例如,使用 Edit | Search All 执行搜索) 突出显示 - 包裹一个对象,以便在转储时以黄色突出显示 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://***.com", "this site"),
  "for answers to programming questions.").Dump();

结果:

查看this site 获取编程问题的答案。

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) new classes and methods have been introduced:

DumpContainer(类) 按需(扩展方法) 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);

【讨论】:

没有什么比作者自己的答案更好的了! Joe,我其实也想制作一些图形作品的原型,然后想转储出一张位图;对于需要一些可视化、处理图形、图像等的此类工作,如果使用 Show 方法会很棒。可能会为未来的其他一些类型提供简洁的可视化。 ...其实只要你能把图形发送到输出面板,剩下的我们可以自己构建扩展。 4.26 beta 允许您通过调用 Util.RawHtml 将 XHTML 注入到输出流中。访问 www.linqpad.net/beta.aspx(或等待几天 RTM)。 Alex - 要将 >1 个东西放到一条线上,请使用 Util.Horizo​​ntalRun【参考方案4】:

Dump 是一个全局扩展方法,SubmitChanges 来自 DataContext 对象,它是一个 System.Data.Linq.DataContext 对象。

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

【讨论】:

注意: 在较新版本的 LinqPad 中:点击 .Dump() 或源代码编辑器中的任何其他方法,按 F12 以“反映” .现在已内置到工具中!

以上是关于LINQPad [扩展] 方法 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

csharp LINQPad脚本,用于获取有关当前所选数据库的基本架构信息(假设LINQPad的默认数据上下文创建方法)

安装 Visual Studio 2017 Enterprise 后 LINQPad .net 方法描述不起作用

LinqPad,使用多个数据上下文 - DevForce

使用内置 Linq to SQL 驱动程序在 LinqPad 中运行 Entity Framework Core 查询的更简单方法?

是否可以使用 Mono (Mac) 运行 LINQPad

使用?wsdl URI查询将LinqPad连接到WCF Web服务