Can parameters be constant?

后端 未结 9 1477
终归单人心
终归单人心 2020-12-24 04:39

I\'m looking for the C# equivalent of Java\'s final. Does it exist?

Does C# have anything like the following:

public Fo         


        
相关标签:
9条回答
  • 2020-12-24 04:46

    Unfortunately you cannot do this in C#.

    The const keyword can only be used for local variables and fields.

    The readonly keyword can only be used on fields.

    NOTE: The Java language also supports having final parameters to a method. This functionality is non-existent in C#.

    from http://www.25hoursaday.com/CsharpVsJava.html

    EDIT (2019/08/13): I'm throwing this in for visibility since this is accepted and highest on the list. It's now kind of possible with in parameters. See the answer below this one for details.

    0 讨论(0)
  • 2020-12-24 04:46

    This is now possible in C# version 7.2:

    You can use the in keyword in the method signature. MSDN documentation.

    The in keyword should be added before specifying a method's argument.

    Example, a valid method in C# 7.2:

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

    While the following is not allowed:

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

    Following error will be shown when trying to modify either x or y since they are marked with in:

    Cannot assign to variable 'in long' because it is a readonly variable

    Marking an argument with in means:

    This method does not modify the value of the argument used as this parameter.

    0 讨论(0)
  • 2020-12-24 04:47

    Create an interface for your class that has only readonly property accessors. Then have your parameter be of that interface rather than the class itself. Example:

    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
    }
    

    For structs, create a generic const wrapper.

    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
    }
    

    Its worth noting though, that its strange that you want to do what you're asking to do regarding structs, as the writer of the method you should expect to know whats going on in that method. It won't affect the values passed in to modify them within the method, so your only concern is making sure you behave yourself in the method you're writing. There comes a point where vigilance and clean code are the key, over enforcing const and other such rules.

    0 讨论(0)
  • 2020-12-24 04:49

    If you often run into trouble like this then you should consider "apps hungarian". The good kind, as opposed to the bad kind. While this doesn't normally tries to express constant-ness of a method parameter (that's just too unusual), there is certainly nothing that stops you from tacking an extra "c" before the identifier name.

    To all those aching to slam the downvote button now, please read the opinions of these luminaries on the topic:

    • Eric Lippert
    • Larry Osterman
    • Joel Spolsky
    0 讨论(0)
  • 2020-12-24 05:01

    I know this might be little late. But for people that are still searching other ways for this, there might be another way around this limitation of C# standard. We could write wrapper class ReadOnly<T> where T : struct. With implicit conversion to base type T. But only explicit conversion to wrapper<T> class. Which will enforce compiler errors if developer tries implicit set to value of ReadOnly<T> type. As I will demonstrate two possible uses below.

    USAGE 1 required caller definition to change. This usage will have only use in testing for correctness of your "TestCalled" functions code. While on release level/builds you shouldn't use it. Since in large scale mathematical operations might overkill in conversions, and make your code slow. I wouldn't use it, but for demonstration purpose only I have posted it.

    USAGE 2 which I would suggest, has Debug vs Release use demonstrated in TestCalled2 function. Also there would be no conversion in TestCaller function when using this approach, but it requires a little more of coding of TestCaller2 definitions using compiler conditioning. You can notice compiler errors in debug configuration, while on release configuration all code in TestCalled2 function will compile successfully.

    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;
      }
    
    }
    
    0 讨论(0)
  • 2020-12-24 05:04

    I'll start with the int portion. int is a value type, and in .Net that means you really are dealing with a copy. It's a really weird design constraint to tell a method "You can have a copy of this value. It's your copy, not mine; I'll never see it again. But you can't change the copy." It's implicit in the method call that copying this value is okay, otherwise we couldn't have safely called the method. If the method needs the original, leave it to the implementer to make a copy to save it. Either give the method the value or do not give the method the value. Don't go all wishy-washy in between.

    Let's move on to reference types. Now it gets a little confusing. Do you mean a constant reference, where the reference itself cannot be changed, or a completely locked, unchangeable object? If the former, references in .Net by default are passed by value. That is, you get a copy of the reference. So we have essentially the same situation as for value types. If the implementor will need the original reference they can keep it themselves.

    That just leaves us with constant (locked/immutable) object. This might seem okay from a runtime perspective, but how is the compiler to enforce it? Since properties and methods can all have side effects, you'd essentially be limited to read-only field access. Such an object isn't likely to be very interesting.

    0 讨论(0)
提交回复
热议问题