C #은 왜 C처럼 로컬 정적 변수를 지원하지 않습니까?
C #에 C와 같은 로컬 정적 변수가없는 이유는 무엇입니까? 나는 그것을 놓친다 !!
대리자를 사용하여 시뮬레이션 할 수 있습니다 ... 다음은 내 샘플 코드입니다.
public Func<int> Increment()
{
int num = 0;
return new Func<int>(() =>
{
return num++;
});
}
다음과 같이 부를 수 있습니다.
Func<int> inc = Increment();
inc();
그들이 망쳐 서 자신에게 맞는 유용한 기능을 생략했기 때문입니다.
어떻게 코딩해야하는지, 무엇이 현명한 지, 그리고 삶의 방식을 재고해야하는지에 대한 모든 논쟁은 방대한 변명입니다.
물론, C #은 순수하고 차마 칼릿 지향적입니다. 이것이 람다 함수에 대한 영구 로컬을 자동 생성하는 이유입니다. 모두 너무 복잡합니다. 너무 멍청 해.
루프 범위 정적은 많은 경우에 유용하고 중요합니다.
짧고 실제적인 대답은 로컬 정적을 클래스 범위로 이동하고 C #에서 클래스 네임 스페이스 오염과 함께 살아야한다는 것입니다. 불만 사항을 시청으로 가져 가십시오.
상태는 일반적으로 메서드의 일부가 아니라 객체의 일부 또는 유형의 일부입니다. (물론 캡처 변수는 예외입니다.)
로컬 정적 변수에 해당하는 것을 원하면 인스턴스 변수 또는 정적 변수를 만들고 메서드 자체가 실제로 해당 상태를 가진 다른 유형의 일부 여야하는지 고려하십시오.
MSDN 블로그 항목 C #이 정적 메서드 변수를 지원하지 않는 이유는 무엇입니까? 원래 게시물에서 질문 한 정확한 질문을 처리합니다.
C #에이 기능이없는 데에는 두 가지 이유가 있습니다.
첫째, 클래스 수준의 정적을 사용하여 거의 동일한 효과를 얻을 수 있으며 메서드 정적을 추가하려면 복잡성이 증가해야합니다.
둘째, 메서드 수준 정적은 코드가 반복적으로 호출되거나 여러 스레드에서 호출 될 때 문제를 일으키는 것으로 악명이 높으며 정의가 메서드에 있기 때문에 정의를 찾기가 더 어렵습니다.
[저자 : Eric Gunnerson]
나는 C #만큼 C에 익숙하지는 않지만, 하나의 메서드에만 사용되는 클래스 수준 정적을 사용하여 로컬 정적으로 할 수있는 모든 것을 수행 할 수 있다고 믿습니다. 분명히 이것은 약간의 구문 변경과 함께 제공되지만 필요한 모든 기능을 얻을 수 있다고 생각합니다.
또한 Eric Lippert는 블로그 에서 이와 같은 질문 에 많은 답변을 합니다. 일반적으로 대답 이 방법 왜 기능 X를 구현하지 않습니다 C # "나는 질문하고" "항상 대답은 항상 같은 수 있습니다 :?. 아무도는 이제까지 설계되지 지정, 구현, 테스트, 문서화 및 기능 것을 제공하기 때문이다. " 본질적으로 그의 대답은 일반적으로 어떤 기능을 추가하는 데 비용이 들기 때문에 비용 편익 분석의 긍정적 인 측면에서 나오지 않았기 때문에 많은 잠재적 기능이 구현되지 않았습니다.
그래서 당신은 당신의 방법에 정적 지역 변수를 사용하고 싶습니까? 축하합니다! 진정한 프로그래머 가되기위한 또 다른 발걸음을 내디뎠습니다 .
정적 지역은 "깨끗한"것이 아니라 "가독성"을 저해하고 미묘하고 찾기 어려운 "버그"로 이어질 수 있다고 말하는 모든 사람들의 말을 듣지 마십시오. 무의미한 말! 그들은 프로그래머 가되고 싶어서 그렇게 말합니다 ! 그들 중 많은 사람들은 아마도 자유 시간 동안 난해한 기능적 프로그래밍 언어를 가지고 장난을 치고있을 것입니다. 당신은 믿을 수 있습니까? 멋쟁이들!
진짜 프로그래머는 내가 전화를 좋아 패러다임 수용 SDD를 - S의 IDE 효과 D 떨어져 나간 D esign에를 . 다음은 가장 중요한 법률 중 일부입니다.
예측할 수 없습니다! 메서드에서 동일한 것을 두 번 반환하지 마십시오. 똑같은 인수로 호출되는 경우에도 마찬가지입니다!
나사 순도-더러워 지자! 상태는 본질적으로 변화를 갈망합니다. 왜냐하면 그것은 다원적 내분비 제 범주에서 만족할 수없는 단일체 이기 때문입니다. 즉 가능한 한 많은 협력자들이 만지는 것을 좋아하기 때문입니다. 그것을 할 기회를 놓치지 마십시오!
부작용 기반 방식으로 코딩하는 데 사용되는 도구 중에는 물론 정적 지역 변수가 있습니다. 그러나 아시다시피 C #은이를 지원하지 않습니다. 왜? 지난 20 년 동안 Microsoft는 유연성과 제어보다 유지 관리를 선호하는 소위 Clean Coder에 의해 침투 해 왔습니다 . 우리가 사랑하는 블루 스크린을 마지막으로 본 기억이 있습니까? 이제 그게 누구의 잘못인지 맞춰보세요!
그러나 두려워하지 마십시오! 실제 개발자는 이러한 잘못된 설계 결정으로 인해 고통을 겪을 필요가 없습니다. 이전에 언급했듯이 람다의 도움으로 일종의 정적 인 지역 변수를 가질 수 있습니다.
그러나 제공된 솔루션은 그다지 만족스럽지 않았습니다. 이전 답변을 사용하면 거의 SDD를 준수하는 코드는 다음과 같습니다.
var inc = Increment();
var zero = inc();
var one = inc();
또는
var zero = Increment()();
그러나 그것은 단지 어리석은 일입니다. 심지어 지망생 개발자는 것을 알 수 있습니다 Increment()
정상적인 방법이 아닙니다 의심 받게됩니다. 반면에 실제 프로그래머는 더 SDD와 비슷하게 만들 수 있습니다. 그 또는 그녀는 우리가 속성이나 필드에 유형을 제공하여 메서드처럼 보이게 만들 수 있다는 것을 알고 있습니다 Func<T>
! 카운터를 초기화하고 캡처 된 카운터를 증가시키는 또 다른 람다를 반환하는 람다를 실행하여 초기화하면됩니다!
다음은 적절한 SDD 코드입니다.
public Func<int> Increment = new Func<Func<int>>(() =>
{
var num = 0;
return () => num++;
}).Invoke();
(위의 내용이 IIFE 라고 생각 하십니까? 네, 맞습니다. 부끄러워해야합니다.)
이제 호출 Increment()
할 때마다 다른 것을 반환합니다 .
var zero = Increment();
var one = Increment();
물론 카운터가 인스턴스의 수명 동안 유지 되도록 만들 수도 있습니다 .
그것은 프로그래머가되고 싶어한다는 것을 보여줄 것입니다 !
C #은 구성 요소 지향 언어이며 클래스 또는 로컬 메서드의 범위를 벗어난 변수 개념이 없습니다. 메서드 내의 변수는 C에서 수행하는 데 익숙 할 수 있으므로 정적으로 선언 할 수 없습니다. 그러나 항상 클래스 정적 변수를 대체로 사용할 수 있습니다.
일반적으로 메서드 수준 정적을 사용하지 않고 C #에서 프로그래밍 문제를 해결하는 방법이 있습니다. 상태는 일반적으로 메서드가 아니라 클래스와 유형으로 디자인해야하는 것입니다.
논리적으로 그렇습니다. 해당 메서드에서만 사용 된 클래스 수준 정적 멤버와 동일합니다. 그러나 메서드 수준 정적 멤버는 더 캡슐화됩니다. 멤버에 저장된 데이터가 단일 메서드에서만 사용되는 경우 해당 단일 메서드로만 액세스 할 수 있어야합니다.
그러나 중첩 클래스를 만들어 C #에서 거의 똑같은 효과를 얻을 수 있습니다.
클래스에 대한 공개 정적 필드를 생성하면 로컬 정적 개념도 쉽게 해결할 수 있다고 생각합니다. 논리적 변화가 거의 없다고 생각하십니까?
큰 논리적 변화라고 생각한다면 어떻게하는지 듣고 싶습니다.
class MyClass
{
public static float MaxDepthInches = 3;
private void PickNose()
{
if (CurrentFingerDepth < MyClass.MaxDepthInches)
{
CurrentFingerDepth++;
}
}
}
이를위한 해결 방법으로 중첩 클래스를 사용할 수 있습니다. C #은 정적 변수의 범위를 클래스로 제한하므로 중첩 클래스를 범위로 사용할 수 있습니다.
예를 들면 :
public class Foo {
public int Increment() {
return IncrementInternal.Increment();
}
private static class IncrementInternal {
private static int counter = 0;
public static int Increment() {
return counter++;
}
}
}
Here Foo
supports Increment
method, but its support it by the private nested class IncrementInternal
which contains the static variable as a member. And of course, counter
is not visible in the context (other methods) of Foo
.
BTW, if you want to access to Foo
context (other members and methods) inside IncrementInternal.Increment
, you can pass this
as a parameter to IncrementInternal.Increment
when you call it from Foo
.
To keep the scope as small as possible, I'm suggesting to create a nested class per each such method. And because it is probably not so common, the number of nested classes will stay small enough to maintains it.
I think it is cleaner than anonymous functions or IIFE.
You can see a live demo here.
Because static local variables are tied to the method, and the method is shared amongst all instances.
I've had to correct myself and other programmers who expect it to be unique per class instance using the method.
However, if you make it a static class, or static instance of a class, it's syntactically clear whether there's an instance per container-class, or one instance at all.
If you don't use these, it becomes easier to refactor later as well.
I don't see much added benefit to local statics, if you are keeping your classes single purpose and small, there is little problem with global static pollution as the naysayers like to complain about. But here is just one other alternative.
using System;
using System.Collections;
public class Program
{
delegate bool DoWork();
public static void Main()
{
DoWork work = Foo().GetEnumerator().MoveNext;
work();
work();
work();
}
public static IEnumerable Foo()
{
int static_x = 10;
/*
do some other static stuff....
*/
main:
//repetative housework
Console.WriteLine(static_x);
static_x++;
yield return true;
goto main;
}
}
If you can imagine some sort of Lippert/Farnsworth hybrid entity announcing GOOD NEWS EVERYONE!, C# 6.0 allows the using static
statement. This effectively allows you to import static class methods (and, it seems, properties and members as well) into the global scope.
In short, you can do something like this:
using NUnit.Framework;
using static Fizz.Buzz;
class Program
{
[Test]
public void Main()
{
Method();
int z = Z;
object y = Y;
Y = new object();
}
}
namespace Fizz
{
class Buzz
{
public static void Method()
{
}
public static int Z;
public static object Y { get; set; }
}
}
While this is only available in C# 6.0, from what I understand the generated assemblies should be compatible with previous .NET platforms (correct me if I'm wrong).
'IT TIP' 카테고리의 다른 글
CSS를 통해 높이와 너비가 다른 모든 이미지를 동일하게 만들려면 어떻게해야합니까? (0) | 2020.11.25 |
---|---|
Pandas 데이터 프레임의 마지막 데이터 행을 삭제하는 방법 (0) | 2020.11.25 |
벡터를 반복하고 특정 항목을 제거합니다. (0) | 2020.11.25 |
모든 환경 변수를 C / C ++로 인쇄 (0) | 2020.11.25 |
3D 벡터의 회전? (0) | 2020.11.25 |