LINQPad [扩展]方法

Ben*_*sen 133 .net c# entity-framework linqpad linq-to-sql

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

.Dump()

SubmitChanges()
Run Code Online (Sandbox Code Playgroud)

Joe*_*ari 237

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

typeof (int).Assembly.Dump ();
typeof (int).Assembly.Dump ("mscorlib");
Run Code Online (Sandbox Code Playgroud)

您还可以指定最大递归深度以覆盖默认的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
Run Code Online (Sandbox Code Playgroud)

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

typeof (Uri).GetMethod ("GetHashCode").Disassemble().Dump();
Run Code Online (Sandbox Code Playgroud)

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

  • Cmd - 执行shell命令或外部程序
  • CreateXhtmlWriter - 创建一个使用LINQPad的Dump()格式化程序的文本编写器
  • SqlOutputWriter - 返回写入SQL输出窗口的文本编写器
  • GetMyQueries,GetSamples - 返回表示已保存查询/样本的对象集合(例如,使用"编辑"|"全部搜索"执行搜索)
  • 突出显示 - 包裹对象,以便在倾倒时以黄色突出显示
  • 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();
Run Code Online (Sandbox Code Playgroud)

你可以将它与Util.HorizontalRun:

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

结果:

查看此站点以获取编程问题的答案.

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();
Run Code Online (Sandbox Code Playgroud)

您也可以在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);
  }
}
Run Code Online (Sandbox Code Playgroud)

在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";
Run Code Online (Sandbox Code Playgroud)

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

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

要使用它:

Customers.OnDemand("Customers").Dump(); // description is optional
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 也许我最终会通过StackOverflow编写手册:) (41认同)
  • 没有比作者自己的回答更好的了! (30认同)
  • 4.26 beta允许您通过调用Util.RawHtml将XHTML注入输出流.请访问www.linqpad.net/beta.aspx(或等待几天进行RTM). (3认同)

Mat*_*att 124

Besides the well-known myQuery.Dump("Query result:"), another feature to mention is the Util class: It contains many quite handy methods (some of them I've mentioned, but there are a lot more).

Also interesting is that you can easily modify the way Dump() works.

Finally I'll show you how you can make changes permanent (i.e. insert, update, delete LINQ queries) using SubmitChanges() or SaveChanges() as well as how you can access the internal connection object of LinqPad.

And to round it up, I'll show you how you can create simple 2d graphic inside of LinqPad (drawing lines, bitmaps or functions).

所以,这里有一系列内置的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
Run Code Online (Sandbox Code Playgroud)

第一示例仅打印变量ac与生皮bd,所述第二例子则正好相反(注意,仅指定可用的参数的2).变量yz不能单独隐藏,因为它们不在顶层.

The following parameters are available (all are optional):

  • description [string] - provides a description for the object to dump
  • depth [int?] - limits how deep the objects are recursively inspected
  • toDataGrid [bool] - if true, the output is formatted as a datagrid rather than as RichText
  • exclude [string] - if you provide a comma-separated list of variables, they will be excluded from the output (in the example "a,c": b and d are shown, a and c are hidden)
  • exclude [string] with "+" prefix - the prefix inverts the logic of the exclude parameter. This means, if you provide a comma-separated list of variables, all except the ones specified are hidden (in the example "+b,d": b and d are shown, all others hidden)
  • store included and excluded properties in a variable (new since LinqPad V5.09.04):
    var x=Util.ToExpando(obj, "a, c", "b, d"); x.Dump();
    The first string contains a list of properties to include, the second string a list to exclude
  • expand on click: If you use .OnDemand("click me").Dump(); instead of .Dump(), it will display a link you can click on to expand. Useful if you want to inspect values, e.g. Util.OnDemand("Customer-ID: " + customerObject.ID.ToString(), ()=>customerObject, false).Dump(); to always show the ID per default but reveal the details of customerObject only if you're interested in.

More advanced topics about Dump can be found here.


Environment

This is not a LinqPad extension, but rather a .NET class, but since it is useful, I'll mention it anyway. You can get a lot of useful information you can use in your scripts such as :

Environment.UserDomainName.Dump();
Environment.MachineName.Dump();
Environment.UserName.Dump();
Environment.CurrentDirectory.Dump();
Environment.SystemDirectory.Dump();
Run Code Online (Sandbox Code Playgroud)

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


Util.WriteCsv

(新:LinqPad版本v4.45.05(测试版)以来可用)

Util.WriteCsv (Customers, @"c:\temp\customers.csv");
Run Code Online (Sandbox Code Playgroud)

这会将表的内容写入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();
    
    Run Code Online (Sandbox Code Playgroud)

    This example returns all elements having the attribute attr1 which contains the value "a" from an XML file which has the same name as the query and is contained in the same path. Check out this link for more code samples.


Util.GetPassword

var pwd = Util.GetPassword("UserXY");
Run Code Online (Sandbox Code Playgroud)

This will retrieve the password from LinqPad's built in password manager. To create & change the password, open the "Password manager" menu item in the "File" menu of LinqPad. If there is no such password saved when you run the C# code, a password dialog will open up asking you for the password and you have the choice to create and save it on the fly by checking the save password checkbox (in the example, the password for "UserXY" would be saved, and later on you can find this entry in the Password manager).

Advantages are that you can store the password in the LinqScripts you create securely, separately and encrypted in Windows' user profile (it is stored in %localappdata%\LINQPad\Passwords as a file). LinqPad uses Windows DPAPI to protect the password.

Also, the password is stored centrally, so if you need to change it, you can do it in the menu and it immediately applies to all scripts you've created.

Notes:

  • If you don't want to save the password and just bring up a password dialog, you can use the 2nd parameter as follows:
    var pwd = Util.GetPassword("UserXY", true);
    This will uncheck the save password checkbox in the password dialog (however, the user is still able to check it and choose to save anyway).

  • If you require the password to be stored in a SecureString, you can use this helper function (n.b.: to get the extension method .ToSecureString() used, please follow this link at Stackoverflow - it also allows you to convert it back if needed):
    System.Security.SecureString GetPasswordSecure(string Name, bool noDefaultSave=true)
    {
      return Util.GetPassword(Name, noDefaultSave).ToSecureString();
    }


Util.Cmd

This method works like a command processor. You can invoke all commands you know from the Windows console.

Example 1 - dir:

Util.Cmd(@"dir C:\");
Run Code Online (Sandbox Code Playgroud)

This will output the result of the directory without the need to .Dump it. Storing it in a variable has the advantage that you can use further Linq queries on it. For example:

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();
Run Code Online (Sandbox Code Playgroud)

This will dump all files with file extensions ".exe" or ".dll" contained in C:\windows\system32. The /s switch is used to recurse all subdirectories and /b is used for bare output format. Note that the second parameter of the Cmd method is specified to suppress the console output in order to show only the filtered result using the Dump method.

You can see that this is more flexible than the wildcards you have with dir since you can use the full flexibility of Linq's query engine.

Example 2 - text editor:

You can open a file in Notepad like this:

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

Util.Image

Displays images from an URL. Example:

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

Util.ProgressBar, Util.Progress

Using Util.ProgressBar allows you to display a progress bar. You can use the following helper class:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Simply use it as the following example shows:

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

You can alternatively use Util.Progress to update LinqPads integrated progress bar, for example:

Util.Progress = 25; // 25 percent complete
Run Code Online (Sandbox Code Playgroud)

The difference is that it will not display in the results window, and you can't assign a message to it.


Util.RawHtml

Displays HTML in the output window. Example:

Util.RawHtml (new XElement ("h1", "This is a big heading")).Dump();
Run Code Online (Sandbox Code Playgroud)

Hyperlinq, Util.HorizontalRun

You can use this example function

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);
}
Run Code Online (Sandbox Code Playgroud)

to show hyperlinks in the result window - or any actions like opening your favourite editor. Usage:

ShowUrl("http://stackoverflow.com", "Check out StackOverflow");
Run Code Online (Sandbox Code Playgroud)

Note that this function always works, while new Hyperlinq ("http://myURL", "Web site").Dump(); does not work for some kind of URLs (especially, if you have to pass port names like ":1234" as part of the URL).


Util.ReadLine

Reads input from the console. Example:

int age = Util.ReadLine<int> ("Enter your age");
Run Code Online (Sandbox Code Playgroud)

As a synonym for Util.ReadLine<string>(), you can use Console.ReadLine() as well.

But there is more! You can create a simple JSON parser with the following snippet - quite useful, for example if you want to parse and test a JSON string on the fly. Save the following snippet as JSONAnalyzer.linq using a text editor and then open it in LinqPad (this is to add the references easily on the fly):

<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");
}
Run Code Online (Sandbox Code Playgroud)

Now you can run it and simply paste a JSON string from the clipboard into the console - it will use the Dump function to display it as an object nicely - and you also get the error messages of the parser on the screen to fix issues. Very useful for debugging AJAX.

JSON


Util.ClearResults

If you need to clear the results window inside your script, use:

Util.ClearResults();
Run Code Online (Sandbox Code Playgroud)

Either use it at the beginning of your script, or - if you're running multiple queries in a script - you should wait for user input before blanking the screen (e.g. by preceding it with Util.ReadLine).


Custom .Dump() - ICustomMemberProvider

Also interesting is, that you can influence the output of the .Dump() method. Simply implement the interface ICustomMemberProvider, e.g.

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
}
Run Code Online (Sandbox Code Playgroud)

If you create an instance of this class, like

var obj1 = new test();
obj1.Dump("Test");
Run Code Online (Sandbox Code Playgroud)

then it will output only Hint, constMember1, constMember2, and myprop, but not property xyz:

Linqpad dump


Displaying a MessageBox or InputBox in LinqPad

If you need to display a messagebox, look here how to do it.

For example, you can display an InputBox by using the following code

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
    }
}
Run Code Online (Sandbox Code Playgroud)

(don't forget to press F4 and add Microsoft.VisualBasic.dll and its namespaces to make this work)


Util.Run

(new: available since LinqPad version v4.52.1 (beta))

Allows you to run another LINQPad script from within your script or within your own .NET program or Windows service (by referencing the LINQPad4-AnyCPU version of LINQPad.exe). It executes the script just as the command line tool lprun.exe would do it.

Examples:

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

This example runs the script foo.linq, which contains the following sample code:

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");
}
Run Code Online (Sandbox Code Playgroud)

It allows you to distinguish if the script was run from inside the LinqPad GUI or via lprun.exe or with Util.Run.

Note: The following variants of invocation might be helpful:

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
Run Code Online (Sandbox Code Playgroud)

SubmitChanges() - Linq To SQL

If you're using LinqToSQL, you might want to make changes permanent (for insert/update/delete operations). Since the database context is implicitly made by LinqPad, you need to call SubmitChanges() after each change as shown below.

Examples for (LinqPad-)Northwind database:

Insert

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

Update

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

Delete

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

Note: In order to get valid IDs for the previous examples, you can use:

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

var pID = Products.Count()+1;
Run Code Online (Sandbox Code Playgroud)

before you invoke them.


SaveChanges() - Entity Framework

If you're using Entity Framework, you might want to make changes permanent as well (for insert/update/delete operations). Since the database context is implicitly made by LinqPad, you need to call SaveChanges() after each change as shown below.

The examples are basically the same as before for LinqToSQL, but you need to use SaveChanges() instead, and for inserting and deleting the methods have changed as well.

Insert

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

Update

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

Delete

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

Note: In order to get valid IDs for the previous examples, you can use:

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

var pID = Products.Count()+1;
Run Code Online (Sandbox Code Playgroud)

before you invoke them.


this - database context

In LinqPad, the database context is established automatically by using the combobox at the top and picking the right database for your query. But sometimes, it is useful to reference it explicitly, for example if you copy some code from your project out of Visual Studio, and paste it into LinqPad.

Your code snippet taken from the Visual Studio project very likely looks like this:

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

Now what to do with dc? Of course, you could remove every occurrence of dc. in your query, but it is much easier. Just add

var dc=this; // UserQuery
Run Code Online (Sandbox Code Playgroud)

to the top of your snippet like so:

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(); 
}   
Run Code Online (Sandbox Code Playgroud)

and the code will work instantly!


this.Connection

Using LinqPad with OleDb, converting a datatable to Linq object, SQL queries in Linq

The following code snippet helps you to use LinqPad with OleDb. Add System.Data.OleDb from the System.Data assembly to the query properties, then paste the following code into 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();
Run Code Online (Sandbox Code Playgroud)

Now add a SqlServer connection to LinqPad and add the Northwind database in order to run this example.

N.B.: If you just want to get the database and server of the currently selected connection, you can use this code snippet:

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();
}
Run Code Online (Sandbox Code Playgroud)

You can even convert myDS into Linq, the answers to the following question show how to do it: Nice examples of using .NET 4 dynamic keyword with Linq

One more example: Suppose your DBA gives you a SQL query and you want to analyze the results in LinqPad - of course in Linq, not in SQL. Then you can do the following:

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;
}
Run Code Online (Sandbox Code Playgroud)

In this example the DBA's SELECT query is just "thrown into" the command text, and the results are filtered and ordered by City.
Of course, this is a simplified example, your DBA would probably support you with a more complex script, but you're getting the idea: Just add a supporting result class which contains all the fields from the SELECT clause and then you can directly use it.
You can even take the result from a stored procedure this way and use it in Linq. As you can see, in this example I don't care about the data type and use dynamic to express it.
So this is really about rapid programming to be able to analyze data quickly. You shouldn't do this in your real application for various reasons (SQL injection, because you can use EF from the beginning etc).


PanelManager

Draw graphic in LinqPad, part 1

To use the examples below, press F4 and add System.Windows.dll, System.Windows.Forms.dll, WindowsFormsIntegration.dll, PresentationCore.dll and PresentationFramework.dll to your LinqPad program and also add the namespace System.Windows.Shapes.

The 1st example simply draws a line:

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");
Run Code Online (Sandbox Code Playgroud)

The 2nd example shows how you can display graphic in LinqPad by using the PanelManager. Normally LinqPad only supports Wpf objects. This example uses System.Windows.Forms.Integration.WindowsFormsHost to make a Windows.Forms.PictureBox available (it was inspired by 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://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);
}
Run Code Online (Sandbox Code Playgroud)

This will create the following graphic (panel items "Graphic" and "Picture" are added by the examples above):

Showing_Graphic_in_LinqPad

If you want to display the images from the Northwind database, you can do the following:
Change the image file name to "NorthwindPics.jpg", then add the following code at the beginning of the 2nd example's Main() method:

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();
}
Run Code Online (Sandbox Code Playgroud)

It will read the first record from the Employees table and display the picture.

Check out the following links to find out more:
Shapes and basic drawing in WPF
LinqPad custom visualizers

Note: You can achieve the same without the PanelManager as well, as the following example, which I saw here shows:

// 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();
}
Run Code Online (Sandbox Code Playgroud)

It is using the .Dump() command to display it. You can invoke image.Dump() multiple times and it will append the image.


Windows Forms

Draw graphic in LinqPad, part 2

The following example, inspired by this post, is showing how to implement a simple function plotter in Linqpad 5 using C#7:

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;
}
Run Code Online (Sandbox Code Playgroud)

It is using the capability of LinqPad to display Windows forms in the results panel.
Example
Add references (press F4):
System.Drawing.dll, System.Windows.Forms.dll, System.Windows.Forms.DataVisualization.dll
and add all namespaces from these assemblies.


Additional hints/further reading:

  • Want to use LinqPad in Visual Studio? Here's how you can do that.

  • Need to have LinqPad as a "Portable app"? Read here how to do that.

  • Joe's website for LinqPad is always an excellent source. Inside LinqPad, Help -> What's New gives you hints about new functions and methods. The LinqPad Forum also contains helpful hints.

  • Also very helpful: This article about Linq(Pad) debugging.

  • Use lprun.exe for running LINQ queries in your <

    • 喜欢关于Util.ReadLine <string>的提示("输入一些json"); 之前我曾经将它复制到文件中,然后从那里阅读......我真的很喜欢这个提示.谢谢! (2认同)
    • 圣。地狱。此处记录的最佳答案之一。谢谢你!! (2认同)

Mat*_*att 5

第 2 部分,共 2 部分

转到第 1 部分


在我之前的回答中达到了StackOverflow 文本限制,但 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

新查询

void Main()
{
    this.ListTables();
}
Run Code Online (Sandbox Code Playgroud)

重要提示:如果您未连接到数据库,则扩展不可用并且 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

var config1 = MyExtensions.AppSettings();
Run Code Online (Sandbox Code Playgroud)

或喜欢

var config2 = MyExtensions.AppSettings("C:\MyGlobalSettings\appsettings.json");
Run Code Online (Sandbox Code Playgroud)

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

如果您的设置文件包含

{
    "AzureStorage": {
        "StorageConnectionString": "some connection string"
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样访问它

var config = MyExtensions.AppSettings();
string connectionString = config.GetSection("AzureStorage").GetSection("StorageConnectionString").Value.ToString();
connectionString.Dump();
Run Code Online (Sandbox Code Playgroud)

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

JavaScript 函数(使用.Dump()

从LinqPad 的5.42 测试版开始,您可以嵌入 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");
}
Run Code Online (Sandbox Code Playgroud)

在本例中,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像下面这样调用前面的例子:

    // 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");
Run Code Online (Sandbox Code Playgroud)

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

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

var jsFoo = ScriptExtension.CreateJavaScript(
            @"function jsFoo(x) { ...  }"); 
ScriptExtension.RunJavaScript(() => jsFoo, "testparam");
Run Code Online (Sandbox Code Playgroud)

如果你已经添加了辅助函数

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);
}
Run Code Online (Sandbox Code Playgroud)

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


使用 LinqPad 进行单元测试 - xUnit

您知道可以在 LinqPad 中编写单元测试吗?例如,您可以使用 xUnit 框架。对于 LinqPad 的第 5 版,可通过 LinqPad 的 NUGET 支持 - 通过F4- 在对话框中单击Add NUGET....。从 LinqPad 的第 6 版开始,它是内置的(菜单查询 -> 添加 XUnit 测试支持)。以下是如何在LinqPad V5 或 V6 中使用 xUnit的分步说明


.Dump() - 内联更新消息

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

示例 1:

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

转储容器动画

请注意,对于一些更复杂的对象,您可能必须使用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!");
}
Run Code Online (Sandbox Code Playgroud)

工具进度条

也可以使用 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";
}
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明


着色你的转储 - 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();
}
Run Code Online (Sandbox Code Playgroud)

现在,它有什么作用?它基于以下颜色为单元格着色

  • 文件扩展名。文件扩展名.bat.txt.json.cmd.dll.xml.exe对他们每个人不同的颜色(某些共享相同的颜色)。
  • 文件大小。如果大小超过999999 bytes,其单元格将显示为橙色。

这将创建一个转储,如:

颜色转储


多数据库支持

LinqPad 的付费版本(LinqPad 6 Premium)支持一个查询中的多个数据库。如果您想详细了解它是如何工作的,请参阅 StackOverflow:
LinqPad using multiple data contexts 中的这个答案。


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