小编Har*_*lse的帖子

使用Await Async WhenAll与一次性对象

在使用一次性对象时,我遇到了尝试并行处理多个任务(或运行时感觉合适)的问题.在下面的代码片段中,每个Processor对象在完成所需工作之前立即处理.

async public Task ProcessData(IEnumerable<int> data)
{
    var tasks = new List<Task>();

    foreach (var d in data)
    {
        using (var processor = new Processor(d))
        {
            processor.Completed += (sender, e) => { // Do something else };
            tasks.Add(processor.ProcessAsync());
        }
    }

    await Task.WhenAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)

重写代码如下导致每个处理器执行其处理并且然后处理,但这不是运行不依赖于彼此的多个任务的最有效方式.

async public Task ProcessData(IEnumerable<int> data)
{
    foreach (var d in data)
    {
        using (var processor = new Processor(d))
        {
            processor.Completed += (sender, e) => { // Do something else };
            await processor.ProcessAsync();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么第一个例子处理'早期'并给出这种情况的最佳代码模式的例子.

c# design-patterns idisposable async-await

4
推荐指数
1
解决办法
1414
查看次数

在我的终结器中处理我的System.IDisposable对象

StackOverflow上有几个关于如果我的对象管理其他实现的托管对象该怎么做的讨论System.IDisposable.

注意:下面我不是在讨论非托管代码.我完全理解清理非托管代码的重要性

大多数讨论都说如果你的对象拥有另一个实现的托管对象System.IDisposable,那么你也应该实现System.IDisposable,在这种情况下你应该调用Dispose()你的对象所持有的一次性对象.这是合乎逻辑的,因为您不知道您拥有的一次性对象是否使用非托管代码.你只知道另一个对象的创造者认为如果你Dispose不再需要这个对象就打电话会是明智的.

在社区维基编辑的StackOverflow中给出了对Disposable模式的一个非常好的解释:

正确使用IDisposable接口

很多时候,我在上面提到的链接中读到:

"你不知道两个对象被销毁的顺序.完全有可能在你的Dispose()代码中,你试图摆脱的托管对象不再存在."

这让我感到困惑,因为我认为只要任何对象持有对象X的引用,那么对象X就不会也无法完成.

换句话说:只要我的对象持有对象XI的引用,就可以确定对象X没有最终确定.

如果这是真的,那么为什么会这样,如果我在完成之前持有对象的引用,我引用的对象已经完成了?

c# dispose idisposable finalizer

4
推荐指数
1
解决办法
951
查看次数

实体框架一对多,只有一个导航属性:WithRequiredDependant?

使用最新的实体框架,我有一个一对多的类,在多方面只有一个导航属性。

MSDN 中所述:Entity Framework Fluent API - Relationships

单向(也称为单向)关系是指仅在关系的一个端点上而不是在两个端点上定义导航属性。

简化:aSchool有很多Students;School 和 Student 之间存在一对多关系,但 School 没有包含学生集合的属性

class Student
{
    public int Id {get; set;}
    // a Student attends one School; foreign key SchoolId
    public int SchoolId {get; set;}
    public School School {get; set;}
}

class School
{
    public int Id {get; set;}
    // missing: public virtual ICollection<Studen> Students {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

在双向关系中,您可以在 中编写以下流畅的 API OnModelCreating

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Student>()
        .HasRequired(student => …
Run Code Online (Sandbox Code Playgroud)

c# entity-framework ef-fluent-api

4
推荐指数
1
解决办法
2191
查看次数

HttpListener:侦听具有显式主机名的端口(无顶级通配符)

例如,假设我有一台有 IP 的机器183.41.22.22。我想侦听将发送到本地主机上该 IP 的端口 43 的所有 HTTP 消息。事实上,我对发送到该端口的所有消息并不真正感兴趣,只对发送到的消息感兴趣https://183.41.22.22:443/CustomerData/

HttpListener 类的文档说我应该添加一个前缀。他们举了一个例子:http://www.contoso.com:8080/customerData/

这是否意味着在我的情况下我应该添加 prefix https://183.41.22.22:443/CustomerData/?或者我应该使用https://localhost:443/CustomerData/

或者,由于我的计算机专用于此任务,我确信我的计算机上的任何其他人都不应收到发送到端口 443 的任何消息。因此,根据相同的文档,我还可以使用通配符:http://*:443

然而,文档警告:

不应使用顶级通配符绑定(http://*:80/ 和http://+:80 )。顶级通配符绑定会造成应用程序安全漏洞。这适用于强通配符和弱通配符。使用明确的主机名或 IP 地址而不是通配符。

什么是显式主机名?是那个部分吗CustomerData

对于那些感兴趣的人,代码的简化部分(没有适当的可能性结束程序)

using (var httpListener = new HttpListener())
{
    httpListener.Prefixes.Add("https://*:443/");
    httpListener.Start();

    while (true)
    {
        var context = httpListener.GetContext();
        var httpRequest = context.Request();

        // fill the response
        string responseText = this.CreateResponseText(httpRequest);
        byte[] buf = Encoding.UTF8.GetBytes(responseText);
        context.Response.ContentLength64 = buf.Length;
        context.Response.OutputStream.Write(buf, 0, buf.Length);
    };
Run Code Online (Sandbox Code Playgroud)

c# httplistener

4
推荐指数
1
解决办法
2761
查看次数

如何使用 Task.Factory.FromAsync 在 Renci.SshNet.BeginDownload 中异步/等待

我可以访问 Connected Renci.SshNet.SftpClient,用它来获取 sftp 文件夹中的文件序列。用于此目的的函数是

Renci.SshNet.SftpClient.ListDirectory(string);
Run Code Online (Sandbox Code Playgroud)

由于目录中的文件数量巨大,这大约需要 7 秒。我希望能够使用 async/await 和取消令牌使我的 UI 保持响应。

如果 Renci.SshNet 有一个返回任务的 ListDirectoryAsync 函数,那么这将很容易:

async Task<IEnumerable<SftpFiles> GetFiles(SftpClient connectedSftpClient, CancellationToken token)
{
    var listTask connectedSftpClient.ListDirectoryAsync();
    while (!token.IsCancellatinRequested && !listTask.IsCompleted)
    {
        listTask.Wait(TimeSpan.FromSeconds(0.2);
    }
    token.ThrowIfCancellationRequested();
    return await listTask;
}
Run Code Online (Sandbox Code Playgroud)

可惜 SftpClient 没有异步功能。以下代码有效,但在下载过程中不会取消:

public async Task<IEnumerable<SftpFile>> GetFilesAsync(string folderName, CancellationToken token)
{
    token.ThrowIfCancellationRequested();
    return await Task.Run(() => GetFiles(folderName), token);
}
Run Code Online (Sandbox Code Playgroud)

但是,SftpClient 确实具有使用以下函数的异步功能

public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, object state, Action<int> listCallback = null);
Public IEnumerable<SftpFile> EndListDirectory(IAsyncResult asyncResult);
Run Code Online (Sandbox Code Playgroud)

在将 IAsyncResult 代码转换为新的异步和等待模式 …

c# asynchronous task iasyncoperation

3
推荐指数
1
解决办法
6154
查看次数

CopiesList.addAll方法抛出UnsupportedOperationException

List<String> hi = Collections.nCopies(10, "Hi");
List<String> are = Collections.nCopies(10, "Are");

hi.addAll(are);

hi.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

产量

Exception in thread "main" java.lang.UnsupportedOperationException
  at java.util.AbstractList.add(Unknown Source)
  at java.util.AbstractList.add(Unknown Source)
  at java.util.AbstractCollection.addAll(Unknown Source)
  at com.practice.java8.lambdaexp.Test.main(Test.java:14)
Run Code Online (Sandbox Code Playgroud)

我认为AbstractList.add()在JDK中没有实现.这就是为什么它不起作用.

但是,如果我使用CopiesList对象创建一个新的ArrayList对象,它可以工作,因为它将具有正确的add()实现.

我的问题是:为什么CopiesListaddAll 没有 正确的实现?

java

3
推荐指数
2
解决办法
362
查看次数

使用Tasks,Handle AggregateException保持UI响应

如果我的WinForms应用程序启动任务以在执行任务时保持响应,我在处理AggregateException时会遇到问题。

简化的情况如下。假设我的Form有一个相当慢的方法,例如:

private double SlowDivision(double a, double b)
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    if (b==0) throw new ArgumentException("b");
    return a / b;
}
Run Code Online (Sandbox Code Playgroud)

按下按钮后,我希望我的表单显示SlowDivision(3,4)的结果。以下代码会将用户界面挂起一段时间:

private void button1_Click(object sender, EventArgs e)
{
    this.label1.Text = this.SlowDivision(3, 4).ToString();
}
Run Code Online (Sandbox Code Playgroud)

因此,我想开始执行处理任务。该任务完成后,应继续执行将显示结果的操作。为了防止InvalidOperationException,我需要确保从创建标签的线程访问label1,因此需要Control.Invoke:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew ( () =>
    {
        return this.SlowDivision(3, 4);
    })
    .ContinueWith( (t) =>
    {
        this.Invoke( new MethodInvoker(() => 
        {
            this.label1.Text = t.Result.ToString();
        }));
    });
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好,但是如何处理异常,例如,如果我想计算SlowDivision(3,0)?

通常,如果任务抛出未处理的异常,它将通过AggregateException转发到等待线程。许多示例显示以下代码:

var myTask = Task.Factory.StartNew ( () => ...);
try
{
    myTask.Wait();
}
catch …
Run Code Online (Sandbox Code Playgroud)

c# multithreading task aggregateexception

2
推荐指数
1
解决办法
1252
查看次数

通过单独的任务更新BindingSource中的元素

我有一个班,比如说人,有一个Id和一个名字.该类正确实现了INotifyPropertyChanged

另外:有人要求上课人.

我真正的问题是一个更复杂的课程,我把它简化为一个相当简单的POCO,以确定它不是因为我的班级.

本来:

public class Person
{
    public int Id {get; set;}
    public string Name {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

对于更新,它需要实现INofityChanged.完整的代码就在这个问题的最后

StackOverflow:如何正确实现INotifyPropertyChanged

  • 我有一个System.Windows.Forms.Form
  • 此表单有一个BindingSource.
  • 绑定源的DataSource属性设置为我的类Person
  • 我有一个绑定到BindingSource的DataGridView
  • 我已经为绑定源添加了几个Person实例
  • 添加的人员被正确显示.
  • 如果我以编程方式更改bindingsource中的Person,则会正确显示更改的值.

到现在为止还挺好.如果在单独的线程中更改Person,则会出现问题.

我经常收到带有消息的InvalidOperationException

BindingSource不能是自己的数据源.不要将DataSource和DataMember属性设置为引用BindingSource的值.

我想这与更新是在一个等待的异步任务中完成的事实有关.我知道在更新用户界面项之前,您应该检查InvokeRequired是否相应地采取行动.

private void OnGuiItemChanged()
{
    if (this.InvokeRequired)
    {
       this.Invoke(new MethodInvoker(() => { OnGuiItemChanged(); }));
    }
    else
    {
        ... // update Gui Item
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,使用绑定源时,更改将在bindingsource内处理.所以我无法检查InvokeRequired

那么如何更新也存储在非UI线程中的绑定源中的项目?

按要求:类Person的实现和我的表单的一些代码

class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int id = 0;
    private string name = null;
    public int Id …
Run Code Online (Sandbox Code Playgroud)

c# multithreading bindingsource

2
推荐指数
1
解决办法
2693
查看次数

Task.WhenAll(IEnumerable):任务启动两次?

我偶然发现了Task.WhenAll的一个重载,即将 IEnumerable作为参数的重载

public static Task WhenAll(IEnumerable<Task<TResult>> tasks)
Run Code Online (Sandbox Code Playgroud)

我以为我会用以下短程序尝试这个功能.

在Test类中:

// contains the task numbers that has been run
private HashSet<int> completedTasks = new HashSet<int>();

// async function. waits a while and marks that it has been run:
async Task<int> Calculate(int taskNr)
{
     string msg = completedTasks.Contains(taskNr) ?
         "This task has been run before" :
         "This is the first time this task runs";
    Console.WriteLine($"Start task {i} {msg}");

    await Task.Delay(TimeSpan.FromMilliseconds(100));

    Console.WriteLine($"Finished task {taskNr}");
    // mark that this task has …
Run Code Online (Sandbox Code Playgroud)

c# async-await

2
推荐指数
1
解决办法
494
查看次数

DLLImport c ++函数具有char*输入和输出参数

关于使用DllImport的一些特定问题,有很多文章.唉,我常常看到对同一个问题的不同回复.例如,有人说如果c ++函数返回一个char*和一个int*strLen,那么有人会说我应该在我的dllImport语句中使用StringBuilder而其他人说返回byte [],有些人在dllImport中有一个marshall语句,有些人不赞成"T.由于旧的C#/ .net版本,似乎需要一些答案.

所以问题是:如果来自c ++的dll调用相当简单,没有奇怪的调用约定或其他奇怪的项目,如果你有输出char*和size或输入char*和size,相应的DllImport函数应该是什么?

c++ .h
bool SendString(const char* pSendStr, long strSize);
bool ReadString(char* pReadStr, long& readStrSize); 
Run Code Online (Sandbox Code Playgroud)

相应的DllImports是什么?用字符串替换instr和outstr?StringBuilder的?的char []?字节[]?是否需要任何元帅声明?

c# pinvoke dllimport

0
推荐指数
1
解决办法
3000
查看次数

如果仅请求第一个元素,Enumerable.OrderBy 是否对完整列表进行排序

如果有顺序的话。并且您只需要有序序列的第一个元素。Orderby 是否足够聪明,不会对完整序列进行排序?

IEnumerable<MyClass> myItems = ...
MyClass maxItem = myItems.OrderBy(item => item.Id).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

因此,如果询问第一个元素,则仅将具有最小值的项目排序为序列的第一个元素。当询问下一个元素时,对剩余序列中具有最小值的项目进行排序,等等。

或者如果您只想要第一个元素,则完整序列是否完全有序?

添加

显然这个问题不清楚。让我们举个例子。

Sort 函数可以执行以下操作:

  • 创建一个包含所有元素的链表
  • 只要链表包含元素:
    • 取链表的第一个元素为最小
    • 扫描链表的其余部分一次以查找任何较小的元素
    • 从链表中删除最小的元素
    • yield 返回最小元素

代码:

public static IEnumerable<TSource> Sort<TSource, TKey>(
    this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));

    IComparer<TKey> comparer = Comparer<TKey>.Default;

    // create a linkedList with keyValuePairs of TKey and TSource
    var keyValuePairs = source
        .Select(source => new KeyValuePair<TKey, TSource>(keySelector(source), source);
    var itemsToSort = new …
Run Code Online (Sandbox Code Playgroud)

linq performance

0
推荐指数
1
解决办法
656
查看次数

SelfHosting ApiController,如何返回错误

我使用这样的例子来创建一个自托管的API控制器.它可以HttpPostHttpGet一个Customer对象.

获得CustomerId 的(简化)函数是:

[RoutePrefix("test")]
public class MyTestController : ApiController
{
    [Route("getcustomer")]
    [HttpGet]
    public Customer GetCustomer(int customerId)
    {    // as a test: react as if this customer exists:
         return new Customer()
         {
              Id = customerId,
              Name = "John Doe",
         };     
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

这很好用.在我的客户端,我可以通过Id向该测试服务器询问客户,并且我获得具有预期数据的客户.

显然,调用函数知道如何将返回的Customer包装到HttpResponseMessage可以传输到我的客户端的对象(?)中.

下一步:如果找不到客户,则返回错误404.

[Route("getcustomer")]
[HttpGet]
public Customer GetCustomer(int customerId)
{    // as a test: only customer 1 exists
     if (customerId == 1)
     {
         return new Customer() …
Run Code Online (Sandbox Code Playgroud)

c# self-hosting http-status-code-404 asp.net-web-api owin

0
推荐指数
1
解决办法
35
查看次数