Program Tip

매개 변수가 일정 할 수 있습니까?

programtip 2020. 10. 12. 08:07
반응형

매개 변수가 일정 할 수 있습니까?


Java와 동등한 C #을 찾고 final있습니다. 존재합니까?

C #에는 다음과 같은 것이 있습니까?

public Foo(final int bar);

위의 예 bar에서은 읽기 전용 변수이며로 변경할 수 없습니다 Foo(). C #에서이 작업을 수행하는 방법이 있습니까?

예를 들어, 어쩌면 내가 함께 작업 할 긴 방법이 x, y그리고 z일부 개체 (INT)로 좌표를. 함수가 어떤 식 으로든 이러한 값을 변경하지 않아 데이터가 손상되지 않는다는 것을 절대적으로 확신하고 싶습니다. 따라서 읽기 전용으로 선언하고 싶습니다.

public Foo(int x, int y, int z) {
     // do stuff
     x++; // oops. This corrupts the data. Can this be caught at compile time?
     // do more stuff, assuming x is still the original value.
}

불행히도 C #에서는 이것을 할 수 없습니다.

const키워드는 지역 변수 및 필드에 사용할 수 있습니다.

readonly키워드는 필드에 사용할 수 있습니다.

참고 : Java 언어는 메소드에 대한 최종 매개 변수도 지원합니다. 이 기능은 C #에 존재하지 않습니다.

에서 http://www.25hoursaday.com/CsharpVsJava.html

편집 (2019/08/13) : 이것이 허용되고 목록에서 가장 높기 때문에 가시성을 위해 이것을 던지고 있습니다. 이제 in매개 변수 로 가능합니다 . 자세한 내용 아래 답변을 참조하십시오.


이제 C # 버전 7.2에서 가능합니다.

in메소드 서명에 키워드를 사용할 수 있습니다 . MSDN 설명서 .

in키워드는 메소드의 인수를 지정하기 전에 추가해야합니다.

예, C # 7.2의 유효한 메서드 :

public long Add(in long x, in long y)
{
    return x + y;
}

다음은 허용되지 않습니다.

public long Add(in long x, in long y)
{
    x = 10; // It is not allowed to modify an in-argument.
    return x + y;
}

수정을 시도 x하거나 다음 yin같이 표시되어 있기 때문에 다음 오류 가 표시됩니다 .

읽기 전용 변수이므로 'in long'변수에 할당 할 수 없습니다.

in의미 로 인수 표시 :

이 메소드는이 매개 변수로 사용되는 인수의 값을 수정하지 않습니다.


int부분 부터 시작하겠습니다 . int값 유형이며 .Net에서는 실제로 사본을 처리하고 있음을 의미합니다. 메서드에 "이 값의 복사본을 가질 수 있습니다. 이것은 제 복사본이 아니라 귀하의 복사본입니다. 다시는 볼 수 없습니다. 그러나 복사본을 변경할 수는 없습니다."라고 말하는 것은 정말 이상한 디자인 제약입니다. 이 값을 복사해도 괜찮다는 것은 메서드 호출에서 암시 적입니다. 그렇지 않으면 메서드를 안전하게 호출 할 수 없습니다. 메서드에 원본이 필요한 경우 구현 자에게 맡기고 복사본을 만들어 저장합니다. 메소드에 값을 제공하거나 메소드에 값을 제공하지 마십시오. 그 사이에 엉망진창을 일으키지 마십시오.

참조 유형으로 이동하겠습니다. 이제 약간 혼란스러워집니다. 참조 자체를 변경할 수없는 상수 참조 또는 완전히 잠기고 변경할 수없는 개체를 의미합니까? 전자의 경우 기본적으로 .Net의 참조가 값으로 전달됩니다. 즉, 참조 사본을 얻습니다. 따라서 우리는 본질적으로 값 유형과 동일한 상황을 가지고 있습니다. 구현자가 원본 참조를 필요로하는 경우 자체적으로 유지할 수 있습니다.

그것은 우리에게 상수 (잠금 / 불변) 객체를 남깁니다. 이것은 런타임 관점에서 괜찮아 보일 수 있지만 컴파일러가 어떻게 적용합니까? 속성과 메서드는 모두 부작용이있을 수 있으므로 기본적으로 읽기 전용 필드 액세스로 제한됩니다. 그러한 개체는 그다지 흥미롭지 않을 것입니다.


대답 : C #에는 C ++와 같은 const 기능이 없습니다.

나는 Bennett Dill에 동의합니다.

const 키워드는 매우 유용합니다. 예제에서 당신은 int를 사용했고 사람들은 당신의 요점을 얻지 못했습니다. 그러나 매개 변수가 해당 함수 내에서 변경할 수없는 사용자 거대하고 복잡한 객체 인 경우 왜? 그것은 const 키워드의 사용입니다 : 매개 변수는 그 메서드에서 중요하지 않기 때문에 그 메서드 안에서 변경할 수 없습니다. Const 키워드는 매우 강력하며 C #에서는 정말 그리워요.


여기에 많은 반대표를 얻을 수있는 짧고 달콤한 답변이 있습니다. 게시물과 댓글을 모두 읽지 않았으므로 이전에 제안 된 적이 있다면 용서해주십시오.

매개 변수를 불변으로 노출하는 객체에 전달한 다음 메서드에서 해당 객체를 사용하는 것이 어떻습니까?

나는 이것이 이미 고려 된 매우 명백한 해결 방법이라는 것을 알고 있으며 OP는이 질문을함으로써 이것을 피하려고 노력하고 있지만 그럼에도 불구하고 여기에 있어야한다고 느꼈습니다 ...

행운을 빕니다 :-)


읽기 전용 속성 접근 자만있는 클래스의 인터페이스를 만듭니다. 그런 다음 매개 변수가 클래스 자체가 아닌 해당 인터페이스가되도록하십시오. 예:

public interface IExample
{
    int ReadonlyValue { get; }
}

public class Example : IExample
{
    public int Value { get; set; }
    public int ReadonlyValue { get { return this.Value; } }
}


public void Foo(IExample example)
{
    // Now only has access to the get accessors for the properties
}

구조체의 경우 일반 const 래퍼를 만듭니다.

public struct Const<T>
{
    public T Value { get; private set; }

    public Const(T value)
    {
        this.Value = value;
    }
}

public Foo(Const<float> X, Const<float> Y, Const<float> Z)
{
// Can only read these values
}

그래도 주목할 가치가있는 것은, 당신이 구조에 대해 요구하는 것을하고 싶다는 것이 이상하다는 것입니다. 메소드 작성자는 그 메소드에서 무슨 일이 일어나고 있는지를 예상해야합니다. 메서드 내에서 값을 수정하기 위해 전달 된 값에 영향을주지 않으므로 작성중인 메서드에서 자신이 행동하는지 확인하는 것이 유일한 관심사입니다. const 및 기타 규칙을 시행하는 것보다 경계와 깨끗한 코드가 핵심이되는 시점이 있습니다.


이런 문제가 자주 발생하면 "헝가리 앱"을 고려해야합니다. 나쁜 종류 와 반대로 좋은 종류 . 이것은 일반적으로 메소드 매개 변수의 상수 성을 표현하려고 시도하지는 않지만 (너무 이례적 임) 식별자 이름 앞에 추가 "c"를 추가하는 것을 막을 수있는 것은 없습니다.

지금 다운 투표 버튼을 누르려는 모든 분들께 다음 주제에 대한 유명 인사들의 의견을 읽어보십시오.


조금 늦을 수도 있다는 것을 알고 있습니다. 그러나 아직 다른 방법을 찾고있는 사람들에게는 C # 표준의 이러한 제한을 우회하는 다른 방법이있을 수 있습니다. 래퍼 클래스 ReadOnly <T>를 작성할 수 있습니다. 여기서 T : struct. 기본 형식 T 로의 암시 적 변환을 사용합니다. 그러나 wrapper <T> 클래스로의 명시 적 변환 만 사용합니다. 개발자가 ReadOnly <T> 유형의 값으로 암시 적 설정을 시도하면 컴파일러 오류를 적용합니다. 아래에서 두 가지 가능한 용도를 보여 드리겠습니다.

USAGE 1은 변경하려면 발신자 정의가 필요합니다. 이 사용법은 "TestCalled"함수 코드의 정확성 테스트에만 사용됩니다. 릴리스 레벨 / 빌드에서는 사용하지 않아야합니다. 대규모 수학 연산에서는 변환이 과도 해지고 코드가 느려질 수 있기 때문입니다. 나는 그것을 사용하지 않을 것이지만 데모 목적으로 만 게시했습니다.

내가 제안하는 USAGE 2는 TestCalled2 함수에서 디버그 대 릴리스 사용을 보여줍니다. 또한이 접근 방식을 사용할 때 TestCaller 함수에 변환이 없지만 컴파일러 컨디셔닝을 사용하는 TestCaller2 정의의 코딩이 조금 더 필요합니다. 디버그 구성에서 컴파일러 오류를 확인할 수 있지만 릴리스 구성에서는 TestCalled2 함수의 모든 코드가 성공적으로 컴파일됩니다.

using System;
using System.Collections.Generic;

public class ReadOnly<VT>
  where VT : struct
{
  private VT value;
  public ReadOnly(VT value)
  {
    this.value = value;
  }
  public static implicit operator VT(ReadOnly<VT> rvalue)
  {
    return rvalue.value;
  }
  public static explicit operator ReadOnly<VT>(VT rvalue)
  {
    return new ReadOnly<VT>(rvalue);
  }
}

public static class TestFunctionArguments
{
  static void TestCall()
  {
    long a = 0;

    // CALL USAGE 1.
    // explicite cast must exist in call to this function
    // and clearly states it will be readonly inside TestCalled function.
    TestCalled(a);                  // invalid call, we must explicit cast to ReadOnly<T>
    TestCalled((ReadOnly<long>)a);  // explicit cast to ReadOnly<T>

    // CALL USAGE 2.
    // Debug vs Release call has no difference - no compiler errors
    TestCalled2(a);

  }

  // ARG USAGE 1.
  static void TestCalled(ReadOnly<long> a)
  {
    // invalid operations, compiler errors
    a = 10L;
    a += 2L;
    a -= 2L;
    a *= 2L;
    a /= 2L;
    a++;
    a--;
    // valid operations
    long l;
    l = a + 2;
    l = a - 2;
    l = a * 2;
    l = a / 2;
    l = a ^ 2;
    l = a | 2;
    l = a & 2;
    l = a << 2;
    l = a >> 2;
    l = ~a;
  }


  // ARG USAGE 2.
#if DEBUG
  static void TestCalled2(long a2_writable)
  {
    ReadOnly<long> a = new ReadOnly<long>(a2_writable);
#else
  static void TestCalled2(long a)
  {
#endif
    // invalid operations
    // compiler will have errors in debug configuration
    // compiler will compile in release
    a = 10L;
    a += 2L;
    a -= 2L;
    a *= 2L;
    a /= 2L;
    a++;
    a--;
    // valid operations
    // compiler will compile in both, debug and release configurations
    long l;
    l = a + 2;
    l = a - 2;
    l = a * 2;
    l = a / 2;
    l = a ^ 2;
    l = a | 2;
    l = a & 2;
    l = a << 2;
    l = a >> 2;
    l = ~a;
  }

}

If struct is passed into a method, unless it's passed by ref, it will not be changed by the method it's passed into. So in that sense, yes.

Can you create a parameter whose value can't be assigned within the method or whose properties cannot be set while within the method? No. You cannot prevent the value from being assigned within the method, but you can prevent it's properties from being set by creating an immutable type.

The question isn't whether the parameter or it's properties can be assigned to within the method. The question is what it will be when the method exits.

The only time any outside data is going to be altered is if you pass a class in and change one of it's properties, or if you pass a value by using the ref keyword. The situation you've outlined does neither.

참고URL : https://stackoverflow.com/questions/2339074/can-parameters-be-constant

반응형