使用Linq; 怎么办Take的"对立面"?
也就是说,而不是获得前面的n个元素
aCollection.Take(n)
Run Code Online (Sandbox Code Playgroud)
我想获得除了最后n个元素之外的所有元素.就像是
aCollection.Leave(n)
Run Code Online (Sandbox Code Playgroud)
(不要问为什么:-)
编辑
我想我可以这样做aCollection.TakeWhile((x, index) => index < aCollection.Count - n)或者以扩展的形式
public static IEnumerable<TSource> Leave<TSource>(this IEnumerable<TSource> source, int n)
{
return source.TakeWhile((x, index) => index < source.Count() - n);
}
Run Code Online (Sandbox Code Playgroud)
但是在Linq to SQL或NHibernate Linq的情况下,如果生成的SQL处理它并生成类似的内容(对于SQL Server/T-SQL)会很好
SELECT TOP(SELECT COUNT(*) -@n FROM ATable) * FROM ATable 或者其他一些更聪明的SQL实现.
我想没有什么比这更好的了吗?(但编辑实际上不是问题的一部分.)
假设我有一个Simple Factory(SimpleProductFactory),它使用条件参数来确定如何创建Product如下:
public static class SimpleProductFactory
{
public static Product MakeProduct(Condition condition)
{
Product product;
switch(condition)
{
case Condition.caseA:
product = new ProductA();
// Other product setup code
break;
case Condition.caseA2:
product = new ProductA();
// Yet other product setup code
break;
case Condition.caseB:
product = new ProductB();
// Other product setup code
break;
}
return product;
}
}
Run Code Online (Sandbox Code Playgroud)
某个客户端使用此工厂来处理包含以下条件的运行时数据:
public class SomeClient
{
// ...
public void HandleRuntimeData(RuntimeData runtimeData)
{
Product product …Run Code Online (Sandbox Code Playgroud) 从C#7.0开始,throw关键字既可以用作表达式,也可以用作语句,这很好.但是,请考虑这些过载
public static void M(Action doIt) { /*use doIt*/ }
public static void M(Func<int> doIt) { /*use doIt*/ }
Run Code Online (Sandbox Code Playgroud)
在调用时这样
M(() => throw new Exception());
Run Code Online (Sandbox Code Playgroud)
或者甚至喜欢这样(带有语句lambda)
M(() => { throw new Exception(); });
Run Code Online (Sandbox Code Playgroud)
编译器选择M(Func <>)重载,指示throw在这里被视为表达式.如何优雅和明确地强制编译器选择M(Action)重载?
一种方法是这样做
M(() => { throw new Exception(); return; });
Run Code Online (Sandbox Code Playgroud)
但返回语句的原因似乎并不明显,并且存在被下一个开发人员更改的风险,特别是因为Resharper警告无法访问的代码.
(当然我可以更改方法命名以避免重载,但这不是问题.:-)
在 C#8.0 中使用可空引用类型,给出这个简化的代码,其中 T 可以是任何值类型或引用类型,而空值是引用类型 T 实例的有效值:
public class C<T>
{
public T P { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
编译器发出警告CS8618 "Non-nullable property 'P' is uninitialized. Consider declaring the property as nullable."。我怎样才能满足编译器并消除这个警告(不抑制 CS8618)?
是否有我可以应用的属性或类型参数约束?这种情况怎么办?
我想出的最好的是
public T P { get; set; } = default!;
Run Code Online (Sandbox Code Playgroud)
但我希望有一种方法可以在不使用 null-forgiving/“dammit” 运算符('!')的情况下做到这一点。
注意:您不能将属性的类型声明为T?- CS8627。此外,这意味着返回的任何值类型都是Nullable<T>,这不是预期的。(阅读更多关于这个,例如在这里。)
编辑:我注意到这也有效:
public class C<T>
{
public C()
{
P = default;
}
[AllowNull]
public T P { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,我更愿意使用自动属性初始化程序。
使用泛型DataEventArgs<TData>类,而不是在事件声明中声明和使用自定义EventArgs继承类,违反.Net事件"模式"约定?或者在某些情况下考虑不好的做法?
(命名事件args 的命名约定是使用事件名称并附加后缀"EventArgs".使用DataEventArgs<TData>省略事件名称,尽管它显示了传输的数据类型.)
您可能会争辩说,通用DataEventArgs类对扩展是封闭的,例如添加另一个属性,除非您可以修改用于TData的类.
更长的解释:
在声明包含一些数据的标准委托事件时,我理解标准事件"模式"约定是使用通用的EventHandler委托声明它:
public event EventHandler<SomethingHappendEventArgs> SomethingHappend;
Run Code Online (Sandbox Code Playgroud)
具体SomethingHappendEventArgs是什么声明的东西
public class SomethingHappendEventArgs : EventArgs
{
public SomeDataType Value { get; private set; }
public SomethingHappendEventArgs(SomeDataType data)
{
this.Value = data;
}
}
Run Code Online (Sandbox Code Playgroud)
当谷歌搜索时,我注意到有几个Microsoft命名空间提供了一个通用的DataEventArgs类,(包括Microsoft.Practices.Prism.Events).但是,我无法找到任何推荐或约定指示何时使用它而不是自定义事件数据类,如SomethingHappendEventArgs,反之亦然.
所以,只要有一个数据块,我要在事件数据包括,是否有我应使用自定义的事件数据类,像SomethingHappendEventArgs,而不是宣布这样的事件的任何原因?
public event EventHandler<DataEventArgs<SomeDataType>> SomethingHappend;
Run Code Online (Sandbox Code Playgroud)
泛型DataEventArgs可以声明如下:
public class DataEventArgs<TData> : EventArgs
{
public TData Value { get; private set; }
public DataEventArgs(TData value)
{
this.Value = value;
}
}
Run Code Online (Sandbox Code Playgroud)