Is it possible to define a local struct, within a method, in C#?
一个常见的编程最佳实践是"定义尽可能接近使用位置的变量"。
我经常使用结构来创建代码,这些代码在某些地方几乎是自记录的。但是,C强制我在方法之外定义结构。这打破了前面提到的最佳实践——它基本上为整个类创建了一个不需要的全局变量类型。
是否可以像局部变量一样在方法内部定义局部结构,如果不能,您能给我一个窗口,了解C设计人员决定阻止这种情况发生的原因吗?
用例
我正在将电子表格的一部分转换为C代码。我希望在方法中使用局部结构以有组织的方式存储临时信息,而不必求助于范围内全局的数百个独立变量。
更新-c 7.0可能具有此功能!
显然,到2016年8月,这将是C 7.0中的一个功能。
所以C编译器团队同意-哇!
- 您是在谈论结构声明,还是该结构的特定实例?
- 也许匿名类型可以帮助您或tuple<>?匿名类型:基本的bit.ly/dph6io,但我不确定你想要实现什么。也许你可以根据自己的需要展示假声明的例子。
- @Joe-我说的是结构的静态声明,以及一个特定的实例,所以我可以有组织地存储临时计算的结果。出于好奇,我正在将电子表格的一部分转换为C代码。
- @Gravitas——您在上一条评论中提到结构是"静态的"。为什么要在方法内部声明静态结构?这个方法也是静态的吗?可能这才是真正的问题…隐马尔可夫模型?既然我们不再是C++了,为什么不坚持惯例并声明一个私有成员,用于构建本地使用的方法?
- @不幸的是,C不支持在静态或其他方法中定义本地结构。遗憾的是,在方法中存储临时计算结果时,最好使用IntelliSense。局部结构还允许我组织临时计算的结果,由于该结构是方法的局部结构,因此似乎不需要在方法之外定义它。哦,好吧,C是99.99%的完美,所以我想我不能抱怨:)
- @重力——理解。我认为它在我的评论中没有很好地翻译,但是我实际上建议使用一个可用的类型选项,即实际的结构(我知道您引用的限制)。基于投票,看起来您似乎找到了一种使用匿名类型实现目标的方法,所以祝贺您;)。
我认为不允许在方法中定义命名类型。至于原因,我得推测一下。如果一个类型不打算在外部使用,那么它的存在可能是不合理的。
但是,您可以在一个方法中定义匿名类型变量。它有点像结构。妥协。
1 2 3 4
| public void SomeMethod ()
{
var anonymousTypeVar = new { x = 5, y = 10 };
} |
- 我可以想到很多情况,您只在一个方法中使用一个结构——例如,一个复杂的LINQ查询,您可能不希望一个大的结果集引起GC压力。结构可以是一种优雅的方式。
- 另外,匿名类型是类,而不是结构。
- 对于Linq,实践是使用匿名类型,可以将其视为结构的替代。不完全一样,但很接近。
- 关闭Yes,但是我可以看到是否有人想要优化导致GC压力过大的查询,结构可能是一个有吸引力的选择。(我不认为这是OP想要做的,只是指出它只是在一个方法内合法使用结构类型。)
- 不幸的是,由于结构是只读的,并且在定义了匿名类型var(这是我在主要问题中要做的)之后,不能将值重新分配给变量。我想我必须坚持在方法之外定义结构。
- 是的,你是对的。匿名类型变量是只读的。
- @Developer Art-5和Y之间的分号应为逗号:)
- @格雷维塔斯:是的,谢谢。纠正了
这有点晚,但这是我的列表解决方案-使用匿名变量作为方法内部的结构:
1 2 3 4
| var list = new[] { new { sn ="a1", sd ="b1" } }.ToList(); // declaring structure
list .Clear(); // clearing dummy element
list .Add(new { sn ="a", sd ="b"}); // adding real element
foreach (var leaf in list ) if (leaf .sn =="a") break; // using it |
匿名元素(sn和sd)以某种方式是只读的。
您可以使用匿名类型执行类似的操作。以下为MSDN示例:
1
| var v = new { Amount = 108, Message ="Hello" }; |
或
1 2 3 4 5 6 7 8
| var productQuery =
from prod in products
select new { prod .Color, prod .Price };
foreach (var v in productQuery )
{
Console .WriteLine("Color={0}, Price={1}", v .Color, v .Price);
} |
- 不幸的是,如果你想在v中定义变量后重新给变量赋值,这是行不通的,这就是我在主要问题中要做的。我想我必须坚持在方法之外定义结构。
- 是的,没有直接的方法去做你想要的。
不,这是不可能的。如果您使用.NET 4.0,则可以使用Tuple来复制这样的内容。
我不明白为什么你需要这样一个结构-只需使用带有口语名称的变量,这应该不会有任何问题。结合使用类名的显式声明,几乎没有歧义空间。
- 好吧-我很好奇为什么C设计师阻止了这个?
- Tuple<...>类型是类,而不是结构。
- @重力:因为这样做真的没有好处。只需在方法前面定义结构。这将使它们在代码中保持逻辑分组。(如果你喜欢的话,也可以使用#region。)
- 这就是为什么我说"复制"。我看不出这种结构的原因,因为C是一种强类型语言,加上显式的名称变量声明,不需要这样做。
- @Gravitas:他们并没有"阻止"它,而是"不把它作为一个可能的特性"。别忘了,每个特性都有设计、实现和测试成本,同时也使语言变得更加复杂,让每个人都可以学习。
- 请记住,与匿名类型一样,tuple属性、item1、item2等都是只读的,至少最迟为c_5。
您可以在C 4.0中创建一个动态类型来完成这项任务,但这并不是您想要的。
然而,我认为定义变量的最大值接近于它们的使用位置,这意味着变量被引入程序流的位置,而不是类型被声明的位置。我相信大多数类型都有一些可以重用的能力在方法类型中创建限制了您创建对公共数据操作的可重用代码块的能力。
它不是一个结构,但是变量可以帮助你吗?
1
| var person = new {Name ="John", City ="London"}; |
它是强类型的,所以它将被编译时检查
- 不幸的是,如果您在定义了Person之后想要将值重新分配给变量,这将不起作用,这正是我在主要问题中要做的。我想我必须坚持在方法之外定义结构。
您可以在方法中定义一个匿名类型并使用它。匿名类型将是只读的,因此它为您提供结构所需的不可变性。它不会显式地是一个结构,但它将被完全定义并包含在方法中。
1 2 3 4 5
| var myLocalType = new
{
SomeValue ="Foo",
SomeId = 14
}; |
不,这是不可能的。实际应用是什么?仅在单个方法中使用结构的频率有多大?微软可能没有看到任何令人信服的理由来实现这一功能。在可能有用的情况下,我们有匿名类型和匿名方法。