在C#中,我发现索引属性非常有用.例如:
var myObj = new MyClass();
myObj[42] = "hello";
Console.WriteLine(myObj[42]);
Run Code Online (Sandbox Code Playgroud)
但据我所知,没有语法糖支持自己支持索引的字段(如果我错了请纠正我).例如:
var myObj = new MyClass();
myObj.field[42] = "hello";
Console.WriteLine(myObj.field[42]);
Run Code Online (Sandbox Code Playgroud)
我需要这样做的原因是,我已经用我的分类的索引属性,但我 GetNumX(),GetX()和SetX()功能如下:
public int NumTargetSlots {
get { return _Maker.NumRefs; }
}
public ReferenceTarget GetTarget(int n) {
return ReferenceTarget.Create(_Maker.GetReference(n));
}
public void SetTarget(int n, ReferenceTarget rt) {
_Maker.ReplaceReference(n, rt._Target, true);
}
Run Code Online (Sandbox Code Playgroud)
你可能会看到将这些暴露为一个可索引的字段属性会更有意义.我可以编写一个自定义类来实现这一点,每次我想要语法糖,但所有的样板代码似乎都没有必要.
所以我编写了一个自定义类来封装样板,并且可以轻松创建可以编制索引的属性.这样我可以添加一个新属性,如下所示:
public IndexedProperty<ReferenceTarget> TargetArray {
get {
return new IndexedProperty<int, ReferenceTarget>(
(int n) => GetTarget(n),
(int n, ReferenceTarget rt) => SetTarget(n, …Run Code Online (Sandbox Code Playgroud) 在尝试将类型分配给类型的属性时System.Type,为什么我们不能这样做?
foo.NetType = bool;
Run Code Online (Sandbox Code Playgroud)
编译器生成此警告:
"表达预期."
解决它的方法是这样做:
foo.NetType = typeof(bool);
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么我们不能使用第一种方法?难道编译器不够聪明,无法弄清楚我们在这里要完成的工作吗?我们有必要采用第二种方法(typeof)吗?
我今天读到了C#4.0代码合同.似乎验证方法的参数不是null的常见做法如下:
Contract.Requires(p != null);
Run Code Online (Sandbox Code Playgroud)
然而,对于我来说,我必须为我的代码中的每个接口方法的每个参数执行此操作,这似乎是不合理的.在绝大多数情况下,参数预计不为空.我希望有某种机制允许定义一些特定的参数被"允许"为空(类似于Java中的"@Nullable"注释),并且Contracts框架将自动确保其余的不是空值.
除了节省很多时间在这个"样板检查"(以及许多"合同类",除了非空参数之外,根本没有任何条件需要验证),它还会使合同代码更清洁而且更"以逻辑为导向".
我的问题是,有没有办法做到这一点,如果没有,哪里没有,或者可能为什么我的方法在这里错了?
假设我在类中有一个数组或任何其他集合,以及一个返回它的属性,如下所示:
public class Foo
{
public IList<Bar> Bars{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以这样写:
public Bar Bar[int index]
{
get
{
//usual null and length check on Bars omitted for calarity
return Bars[index];
}
}
Run Code Online (Sandbox Code Playgroud) 在过去的几年里,我一直在使用C语言,并且我已经成功地将单一用途的static变量放在我的代码中使用它们的位置附近.
在编写一个需要方法范围静态值的非常基本的方法时,我有点惊讶地发现编译器不喜欢我试图从我的方法中定义一个静态对象.
谷歌搜索已经证实在C#中这是不可能的.不过,我很好奇为什么代码,如下,完全不受限制.
public int incrementCounterAndReturn()
{
static int i = 0;
return ++i;
}
Run Code Online (Sandbox Code Playgroud)
当然,这是一个简单的例子,可以重新定义相同的效果,但这不是重点.方法范围,静态值有它们的位置和目的.哪些设计决策阻止了C#中静态对象的实现?
我们使用的是C#5.0版本,它是2013年.我只能假设这是不可能的,因为它有一个设计选择,而不仅仅是因为"这是一个复杂而难以实现的东西".有没有人有任何内幕消息?
正如标题所说,在System.IO的Directory类中有一个Directory.Move但没有Directory.Copy方法.这有什么理由吗?
更新:
对我来说,复制和移动操作几乎完全相同,唯一的区别是移动操作执行复制然后删除目标.并且错误处理对于移动和复制一样复杂.所以,如果一个实现,为什么不是另一个?
更新2:
这是来自mmclean的评论引用:
Directory.Move然而不移动,它重命名.因此,"目标"路径是指向目录的完整路径,而不是"移入"的位置,并且移动到不同的驱动器是不可能的.
所以我理解移动实际上是一个重命名操作(只有文件分配表中的更改和条目).但是移动和复制命令在合并目标中存在的项目时都会遇到同样的问题(覆盖/保留两者).因此,复制操作唯一增加的复杂性是它必须物理复制文件.但这仍然没有解释不执行它的决定.更是这样,当复制命令在VB.NET中实现并有在MSDN上的复制操作的一个非常简单的实现方式在这里.
一些语言 - 比如Delphi - 有一种非常方便的方法来创建索引器:不仅是整个类,甚至单个属性都可以被编入索引,例如:
type TMyClass = class(TObject)
protected
function GetMyProp(index : integer) : string;
procedure SetMyProp(index : integer; value : string);
public
property MyProp[index : integer] : string read GetMyProp write SetMyProp;
end;
Run Code Online (Sandbox Code Playgroud)
这可以很容易地使用:
var c : TMyClass;
begin
c = TMyClass.Create;
c.MyProp[5] := 'Ala ma kota';
c.Free;
end;
Run Code Online (Sandbox Code Playgroud)
有没有办法在C#中轻松实现同样的效果?
有没有办法做这样的事情:
class blabla
{
string[] a;
string ciao(int row, string text)
{
set { a[row] = text;}
get { return a[row;}
}
}
Run Code Online (Sandbox Code Playgroud)
(是的,我知道我最终可以制作自己的方法)
本博客的最后一部分解释了以下内容:http://lostechies.com/jimmybogard/2010/05/18/caveats-of-c-4-0-optional-parameters/
但我仍然想知道为什么.
我最近遇到了Scala的默认参数.
在Scala中,被调用者为具有默认值的参数提供实际值.因此,不必重新编译所有调用者以使用更新的默认参数值.
如果Scala可以做到,我猜C#也可以做到.
所以为什么?他们为什么设计它容易出错?
编辑:
容易出错可能过于强烈,所以我的问题更像是这样:
为什么它的设计方式是默认参数的版本控制不会影响调用者?
c# scala language-design optional-parameters default-parameters