Bre*_*ias 8 linq lambda linq-to-objects
我的职业生涯始于一个核心功能范式开发人员(LISP),现在我是一个核心的.net/C#开发人员.当然我很迷恋LINQ.但是,我也相信(1)使用正确的工具和(2)保留KISS原则:在我工作的60多名工程师中,可能只有20%有LINQ /功能范例经验,5%有6到12个月的这种经历.简而言之,我觉得有必要远离LINQ,除非我在没有它的情况下实现目标受到阻碍(其中用一行LINQ替换3行OO代码不是"目标").
但现在,拥有12个月LINQ /功能范例经验的工程师之一,正在生产代码中的每个可想到的位置使用LINQ到对象,或者至少使用lambda表达式.我对KISS原则的各种呼吁没有产生任何结果.因此...
我接下来可以申请哪些已发表的研究?什么"编码标准"指南有其他人炮制成功?我可以指出是否发布了LINQ性能问题?简而言之,我试图通过间接说服来实现我的第一个目标 - KISS.
当然,这个问题可以扩展到无数其他领域(例如过度使用扩展方法).也许有一个"超级"指南,备受推崇(例如已发表的研究等),在这方面需要更广泛的考虑.什么?
编辑编辑:哇!我受过教育!我同意我会以完全错误的方式来到这里.但作为澄清,请看下面我实际看到的示例代码.最初它编译和工作,但它的目的现在无关紧要.只要顺其自然的"感觉".现在我半年后再次访问这个样本,我对实际上困扰我的情况有了不同的看法.但是我希望有更好的眼睛比我的评论更好.
//This looks like it was meant to become an extension method...
public class ExtensionOfThreadPool
{
public static bool QueueUserWorkItem(Action callback)
{
return ThreadPool.QueueUserWorkItem((o) => callback());
}
}
public class LoadBalancer
{
//other methods and state variables have been stripped...
void ThreadWorker()
{
// The following callbacks give us an easy way to control whether
// we add additional headers around outbound WCF calls.
Action<Action> WorkRunner = null;
// This callback adds headers to each WCF call it scopes
Action<Action> WorkRunnerAddHeaders = (Action action) =>
{
// Add the header to all outbound requests.
HttpRequestMessageProperty httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add("user-agent", "Endpoint Service");
// Open an operation scope - any WCF calls in this scope will add the
// headers above.
using (OperationContextScope scope = new OperationContextScope(_edsProxy.InnerChannel))
{
// Seed the agent id header
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestMessage;
// Activate
action();
}
};
// This callback does not add any headers to each WCF call
Action<Action> WorkRunnerNoHeaders = (Action action) =>
{
action();
};
// Assign the work runner we want based on the userWCFHeaders
// flag.
WorkRunner = _userWCFHeaders ? WorkRunnerAddHeaders : WorkRunnerNoHeaders;
// This outter try/catch exists simply to dispose of the client connection
try
{
Action Exercise = () =>
{
// This worker thread polls a work list
Action Driver = null;
Driver = () =>
{
LoadRunnerModel currentModel = null;
try
{
// random starting value, it matters little
int minSleepPeriod = 10;
int sleepPeriod = minSleepPeriod;
// Loop infinitely or until stop signals
while (!_workerStopSig)
{
// Sleep the minimum period of time to service the next element
Thread.Sleep(sleepPeriod);
// Grab a safe copy of the element list
LoadRunnerModel[] elements = null;
_pointModelsLock.Read(() => elements = _endpoints);
DateTime now = DateTime.Now;
var pointsReadyToSend = elements.Where
(
point => point.InterlockedRead(() => point.Live && (point.GoLive <= now))
).ToArray();
// Get a list of all the points that are not ready to send
var pointsNotReadyToSend = elements.Except(pointsReadyToSend).ToArray();
// Walk each model - we touch each one inside a lock
// since there can be other threads operating on the model
// including timeouts and returning WCF calls.
pointsReadyToSend.ForEach
(
model =>
{
model.Write
(
() =>
{
// Keep a record of the current model in case
// it throws an exception while we're staging it
currentModel = model;
// Lower the live flag (if we crash calling
// BeginXXX the catch code will re-start us)
model.Live = false;
// Get the step for this model
ScenarioStep step = model.Scenario.Steps.Current;
// This helper enables the scenario watchdog if a
// scenario is just starting
Action StartScenario = () =>
{
if (step.IsFirstStep && !model.Scenario.EnableWatchdog)
{
model.ScenarioStarted = now;
model.Scenario.EnableWatchdog = true;
}
};
// make a connection (if needed)
if (step.UseHook && !model.HookAttached)
{
BeginReceiveEventWindow(model, step.HookMode == ScenarioStep.HookType.Polled);
step.RecordHistory("LoadRunner: Staged Harpoon");
StartScenario();
}
// Send/Receive (if needed)
if (step.ReadyToSend)
{
BeginSendLoop(model);
step.RecordHistory("LoadRunner: Staged SendLoop");
StartScenario();
}
}
);
}
, () => _workerStopSig
);
// Sleep until the next point goes active. Figure out
// the shortest sleep period we have - that's how long
// we'll sleep.
if (pointsNotReadyToSend.Count() > 0)
{
var smallest = pointsNotReadyToSend.Min(ping => ping.GoLive);
sleepPeriod = (smallest > now) ? (int)(smallest - now).TotalMilliseconds : minSleepPeriod;
sleepPeriod = sleepPeriod < 0 ? minSleepPeriod : sleepPeriod;
}
else
sleepPeriod = minSleepPeriod;
}
}
catch (Exception eWorker)
{
// Don't recover if we're shutting down anyway
if (_workerStopSig)
return;
Action RebootDriver = () =>
{
// Reset the point SendLoop that barfed
Stagepoint(true, currentModel);
// Re-boot this thread
ExtensionOfThreadPool.QueueUserWorkItem(Driver);
};
// This means SendLoop barfed
if (eWorker is BeginSendLoopException)
{
Interlocked.Increment(ref _beginHookErrors);
currentModel.Write(() => currentModel.HookAttached = false);
RebootDriver();
}
// This means BeginSendAndReceive barfed
else if (eWorker is BeginSendLoopException)
{
Interlocked.Increment(ref _beginSendLoopErrors);
RebootDriver();
}
// The only kind of exceptions we expect are the
// BeginXXX type. If we made it here something else bad
// happened so allow the worker to die completely.
else
throw;
}
};
// Start the driver thread. This thread will poll the point list
// and keep shoveling them out
ExtensionOfThreadPool.QueueUserWorkItem(Driver);
// Wait for the stop signal
_workerStop.WaitOne();
};
// Start
WorkRunner(Exercise);
}
catch(Exception ex){//not shown}
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 15
嗯,听起来像你是那个想让代码更复杂的人 - 因为你相信你的同事不能达到真正简单的方法.在许多情况下,我发现LINQ to Objects使代码变得更简单 - 是的,确实包括将几行更改为一行:
int count = 0;
foreach (Foo f in GenerateFoos())
{
count++;
}
Run Code Online (Sandbox Code Playgroud)
变得
int count = GenerateFoos().Count();
Run Code Online (Sandbox Code Playgroud)
例如.
在不使代码更简单的情况下,尝试引导他远离LINQ是好的 - 但上面是一个例子,你肯定不会因为避免LINQ而受到严重阻碍,但"KISS"代码显然是LINQ代码.
听起来您的公司可以从训练其工程师利用LINQ to Objects中获益,而不是总是试图吸引最低的共同点.
您似乎将Linq等同于具有更高复杂性的对象,因为您认为不必要地使用它违反了"保持简单,愚蠢".
我的所有经验都是相反的:它使复杂的算法更容易编写和读取.
相反,我现在将命令式,基于语句的状态突变编程视为仅在必要时才使用的"风险"选项.
所以我建议你努力让更多同事了解这些好处.尝试将你的方法限制在你(和其他人)已经理解的方法上是一种虚假的经济,因为在这个行业中,它与"新"实践保持联系会带来巨大的收益(当然,这些东西并不新鲜,但是你指出,这对Java或C#1.x背景的许多人来说是新的.
至于试图对其上的"性能问题"提出一些指控,我认为你不会有太多运气.Linq-to-objects本身涉及的开销微不足道.