在这个问题之后,我试图使用TPL实现异步方法,并尝试遵循TAP指南.
我希望我的异步方法在完成后执行回调.据我所知,有三种方法可以做到这一点.
1)在我的任务委托中手动回调
public Task DoWorkAsync(DoWorkCompletedCallback completedCallback)
{
return Task.Factory.StartNew(
{
//do work
//call callback manually
completedCallback();
});
}
Run Code Online (Sandbox Code Playgroud)
2)在任务委托中为任务分配回调
public Task DoWorkAsync(DoWorkCompletedCallback completedCallback)
{
return Task.Factory.StartNew(
{
//do work
}
).ContinueWith(completedCallback); //assign callback to Task
}
Run Code Online (Sandbox Code Playgroud)
3)在呼叫者中为任务分配回叫
public Task DoWorkAsync()
{
return Task.Factory.StartNew(
{
//do work
});
}
public void SomeClientCode()
{
Task doingWork = DoWorkAsync();
doingWork.ContinueWith(OnWorkCompleted);
}
Run Code Online (Sandbox Code Playgroud)
我的直觉是3更正确,因为它将回调与方法分离,并且意味着客户端代码可以以任何方式管理任务(使用回调,轮询等),这似乎是任务的全部内容.但是,如果DoWorkAsync()在客户端代码挂钩其回调之前完成其工作会发生什么?
是否有一种普遍接受的方式来做到这一点还是全新的?
做2)超过1)有什么好处吗?
我一直在玩弄哪里放"你确定吗?" 在我的MVVM WPF应用程序中输入提示.
我倾向于认为这些纯粹是View的一部分.如果ViewModel公开了一个DeleteCommand
,那么我希望该命令立即删除.
要将这些提示集成到ViewModel中,它必须公开一个单独RequestDeleteCommand
的DeletePromptItem
属性来绑定提示,并且还可以兼作显示提示的触发器.
即使这样,也没有什么能阻止单元测试DeleteCommand
直接调用,除非我在ViewModel中放置特定的逻辑来要求DeletePromptItem
匹配作为参数提供的项目DeleteCommand
.
但是,这对我来说只是看起来像ViewModel中的噪音.提示更像是一个用户界面问题,以防止错误点击等.对我来说,这表明它应该在视图中,确认提示调用DeleteCommand.
有什么想法吗?
我有一个ObservableCollection
项目绑定到我的视图中的列表控件.
我有一种情况需要在集合的开头添加一大块值.
Collection<T>.Insert
documentation将每个插入指定为O(n)操作,每个插入也生成一个CollectionChanged
通知.
因此,我理想地希望在一次移动中插入整个范围的项目,这意味着只有一个基础列表的随机播放,并且希望有一个CollectionChanged
通知(可能是"重置").
Collection<T>
不公开任何执行此操作的方法.List<T>
有InsertRange()
,但是IList<T>
,这Collection<T>
暴露了通过其Items
属性不会.
有没有办法做到这一点?
为什么我不能在简单的结构上使用sizeof()?
例如:
private struct FloatShortPair
{
public float myFloat;
public short myShort;
};
int size = sizeof(FloatShortPair); //CS0233
Run Code Online (Sandbox Code Playgroud)
错误CS0233:'FloatShortPair'没有预定义的大小,因此sizeof只能在不安全的上下文中使用(考虑使用System.Runtime.InteropServices.Marshal.SizeOf)
MSDN声明:
sizeof运算符只能用于编译时常量的类型.如果收到此错误,请确保可以在编译时确定标识符的大小.如果不能,则使用SizeOf而不是sizeof.
float和short如何编译时间常量?8 /
根据MSDN,Monitor.Wait()
:
释放对象的锁定并阻止当前线程,直到它重新获取锁定.
但是,我读过的关于Wait()和Pulse()的所有内容似乎表明仅仅在另一个线程上释放锁是不够的.我需要先调用Pulse()来唤醒等待的线程.
我的问题是为什么?在Monitor.Enter()上等待锁的线程只是在它被释放时获取它.没有必要"唤醒他们".它似乎打败了Wait()的用处.
例如.
static object _lock = new Object();
static void Main()
{
new Thread(Count).Start();
Sleep(10);
lock (_lock)
{
Console.WriteLine("Main thread grabbed lock");
Monitor.Pulse(_lock) //Why is this required when we're about to release the lock anyway?
}
}
static void Count()
{
lock (_lock)
{
int count = 0;
while(true)
{
Writeline("Count: " + count++);
//give other threads a chance every 10th iteration
if (count % 10 == 0)
Monitor.Wait(_lock);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用Exit()和Enter()而不是Wait(),我可以这样做: …
//ok
Action<int> CallbackWithParam1 = delegate { };
//error CS1593: Delegate 'System.Action<int>' does not take 0 arguments
Action<int> CallbackWithParam2 = () => { };
Run Code Online (Sandbox Code Playgroud)
只是想知道为什么差异真的.: - /
固定小数位很容易
String.Format("{0:F1}", 654.321);
Run Code Online (Sandbox Code Playgroud)
给
654.3
Run Code Online (Sandbox Code Playgroud)
如何在C中作为参数输入小数位数?所以
String.Format("{0:F?}", 654.321, 2);
Run Code Online (Sandbox Code Playgroud)
给
654.32
Run Code Online (Sandbox Code Playgroud)
我找不到应该更换的东西?
我发现命名线程在调试时非常有用.
我看不到使用参数命名线程的方法 Task.Factory.StartNew()
那么在任务中明确命名线程是否可以接受?例如:
private void MyFunc()
{
Task.Factory.StartNew(() =>
{
Thread.CurrentThread.Name = "Foobulizer";
Foobulize();
});
}
Run Code Online (Sandbox Code Playgroud)
但是,我知道线程可能会被重用于不同的任务,所以我需要在任务结束时显式重置线程名称吗?这感觉非常hacky所以我认为这可能是一个坏主意,或者有一个正确的方法来做到这一点?
在试图回答这个问题时,我惊讶地发现,当该文件已经存在时尝试创建一个新文件不会抛出一个唯一的异常类型,它只会抛出一个泛型IOException
.
因此,我想知道如何确定它IOException
是现有文件的结果还是其他一些IO错误.
该异常具有HResult,但此属性受到保护,因此对我无法使用.
我能看到的另一种方式是模式匹配感觉糟糕的消息字符串.
例:
try
{
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//write file
}
}
catch (IOException e)
{
//how do I know this is because a file exists?
}
Run Code Online (Sandbox Code Playgroud) 闭包捕获的变量如何与不同的线程交互?在下面的示例代码中,我想将totalEvents声明为volatile,但C#不允许这样做.
(是的我知道这是不好的代码,这只是一个例子)
private void WaitFor10Events()
{
volatile int totalEvents = 0; // error CS0106:
_someEventGenerator.SomeEvent += (s, e) => totalEvents++;
while(totalEvents < 10)
Thread.Sleep(100);
}
Run Code Online (Sandbox Code Playgroud)
编辑:人们似乎忽略了我的问题.我知道我不能volatile
在当地的变种上使用.我也知道示例代码很糟糕,可能以其他方式实现,因此我的"坏代码"免责声明.这只是为了说明问题.
无论如何,似乎没有办法强制将volatile语义强加到捕获的局部变量上,所以我将实现一种不同的方式.谢谢你的回答,无论如何我已经学到了很多有用的东西.:)
c# ×9
.net ×1
arguments ×1
asynchronous ×1
callback ×1
closures ×1
collections ×1
delegates ×1
exception ×1
insert ×1
ioexception ×1
lambda ×1
mvvm ×1
performance ×1
sizeof ×1
struct ×1
volatile ×1
wpf ×1