89

Java の に相当する C# を探していますfinal。それは存在しますか?

C# には次のようなものがありますか。

public Foo(final int bar);

上記の例でbarは、 は読み取り専用変数であり、 では変更できませんFoo()。C#でこれを行う方法はありますか?

たとえば、あるオブジェクト (int) のxy、および座標を操作する long メソッドがあるとします。z関数がこれらの値を変更しないことを絶対に確認したいので、データが破損します。したがって、それらを読み取り専用として宣言したいと思います。

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.
}
4

9 に答える 9

64

残念ながら、C# ではこれを行うことはできません。

キーワードは、constローカル変数とフィールドにのみ使用できます。

キーワードはreadonlyフィールドでのみ使用できます。

注: Java 言語は、メソッドへの最終パラメーターを持つこともサポートしています。この機能は C# にはありません。

http://www.25hoursaday.com/CsharpVsJava.htmlから

編集 (2019/08/13): これは受け入れられており、リストの一番上にあるため、可視性のためにこれを投入します。これは、inパラメーターを使用して可能になりました。詳細については、この下の回答を参照してください。

于 2010-02-26T02:24:18.700 に答える
9

答え: C# には、C++ のような const 機能がありません。

私はベネット・ディルに同意します。

const キーワードは非常に便利です。この例では、int を使用しましたが、人々はあなたの主張を理解していません。しかし、パラメーターがその関数内で変更できないユーザーの巨大で複雑なオブジェクトである場合、なぜでしょうか? それが const キーワードの使用です。パラメーターはそのメソッド内で変更できません。[ここでの理由が何であれ]それはそのメソッドにとって重要ではないためです。Const キーワードは非常に強力で、C# では本当に恋しいです。

于 2011-12-20T18:09:10.933 に答える
8

これは、おそらく多くの反対票を獲得する短くて甘い答えです。すべての投稿とコメントを読んでいないので、これが以前に提案されていた場合はご容赦ください。

パラメータを取得して、それらを不変として公開するオブジェクトに渡し、そのオブジェクトをメソッドで使用してみませんか?

これはおそらくすでに検討されている非常に明白な回避策であり、OPはこの質問をすることでこれを回避しようとしていますが、それでもここにあるはずだと感じました...

幸運を :-)

于 2010-02-26T04:05:42.363 に答える
7

その部分から始めますintintは値型であり、.Net では、実際にコピーを扱っていることを意味します。メソッドに「この値のコピーを作成できます。これはあなたのコピーであり、私のものではありません。二度と表示されません。ただし、コピーを変更することはできません」とメソッドに指示するのは、非常に奇妙な設計上の制約です。メソッド呼び出しでは、この値をコピーしても問題ないことが暗黙的に示されています。そうしないと、メソッドを安全に呼び出すことができませんでした。メソッドにオリジナルが必要な場合は、実装者に任せて、コピーを作成して保存してください。メソッドに値を指定するか、メソッドに値を指定しないでください。途中で意地悪をしないでください。

参照型に移りましょう。ここで、少し混乱します。参照自体を変更できない定数参照、または完全にロックされた変更不可能なオブジェクトを意味しますか? 前者の場合、デフォルトで .Net の参照は値で渡されます。つまり、参照のコピーを取得します。したがって、値型の場合と本質的に同じ状況になります。実装者が元の参照を必要とする場合は、それを自分で保持できます。

これにより、一定の (ロックされた/不変の) オブジェクトが残ります。これはランタイムの観点からは問題ないように見えるかもしれませんが、コンパイラはどのようにそれを強制するのでしょうか? プロパティとメソッドはすべて副作用を持つ可能性があるため、基本的に読み取り専用のフィールド アクセスに制限されます。そのようなオブジェクトはあまり興味深いものではありません。

于 2010-02-26T02:23:25.247 に答える
6

読み取り専用のプロパティ アクセサーのみを持つクラスのインターフェイスを作成します。次に、パラメーターをクラス自体ではなく、そのインターフェイスのものにします。例:

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 やその他の規則を強制するよりも、警戒とクリーンなコードが鍵となるポイントが来ます。

于 2013-08-24T17:05:29.190 に答える
3

私はこれが少し遅れるかもしれないことを知っています。しかし、これについてまだ他の方法を探している人にとっては、C# 標準のこの制限を回避する別の方法があるかもしれません。ラッパー クラス ReadOnly<T> where T : struct. を書くことができます。基本型 T への暗黙的な変換あり。ただし、wrapper<T> クラスへの明示的な変換のみ。開発者が暗黙的に ReadOnly<T> 型の値を設定しようとすると、コンパイラ エラーが強制されます。以下に 2 つの使用例を示します。

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;
  }

}
于 2016-04-30T14:20:28.123 に答える
2

このような問題に頻繁に遭遇する場合は、"apps hangarian" を検討してください。悪い種類とは対照的に、良い種類。これは通常、メソッド パラメーターの定数性を表現しようとはしませんが (これは非常に珍しいことです)、識別子名の前に余分な "c" を追加することを妨げるものは何もありません。

今すぐ下票ボタンをバタンと閉めたくてたまらないすべての人に、トピックに関するこれらの著名人の意見を読んでください。

于 2010-02-26T03:06:33.397 に答える
0

struct がメソッドに渡される場合、ref によって渡されない限り、渡されたメソッドによって変更されることはありません。そういう意味では、そうですね。

メソッド内で値を割り当てることができない、またはメソッド内でプロパティを設定できないパラメーターを作成できますか? いいえ。メソッド内で値が割り当てられるのを防ぐことはできませんが、不変の型を作成することで、そのプロパティが設定されるのを防ぐことができます。

問題は、パラメーターまたはそのプロパティをメソッド内で割り当てることができるかどうかではありません。問題は、メソッドが終了したときにどうなるかです。

外部データが変更されるのは、クラスを渡してそのプロパティの 1 つを変更する場合、または ref キーワードを使用して値を渡す場合だけです。あなたが概説した状況はどちらもしません。

于 2010-02-26T02:15:18.227 に答える