Использование const в C#

Я хотел бы сделать переменную cert ниже, чтобы быть const? Когда я это делаю, я получаю ошибку: "Выражение, назначаемое сертификату, должно быть константой". В Интернете я видел статьи, в которых просили преобразовать их в статические readonly, а не в const, а также говорили, что для того, чтобы быть const, значение должно быть известно во время компиляции.

У меня два вопроса

  1. Разве сертификат не может быть константной переменной, так как я не хочу, чтобы она была изменена?
  2. Я попытался сделать переменную cert доступной только для чтения, и это также выдает мне ошибку "Модификатор только для чтения недопустим для этого элемента".

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IAMAGoodDeveloper
{
    public static class Program
    {
        static void Main(string[] args)
        {
            programStart();
        }

        private static void programStart()
        {
            var myFactory = new MyFactory();
            var secretsProvider = myFactory.GenerateKeyProvider();
            const int cert = secretsProvider.GetKey("arg");
        }
    }
}

MyFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IAMAGoodDeveloper
{
    public class MyFactory
    {
        public KeyGen GenerateKeyProvider()
        {
            return new KeyGen();
        }
    }

    public class KeyGen
    {
        public int GetKey(string arg)
        {
            return 1;
        }
    }
}

5 ответов

Решение

Вы не можете использовать const с созданными объектами. Хорошей альтернативой будет статическое поле только для чтения на уровне класса.

const ключевое слово времени компиляции, которое заменит все ссылки на вашу константную переменную жестко закодированным значением в скомпилированном коде

public class MyClass
{
    private const int MyNumber = 2;

    public void MyMethod()
    {
        Console.WriteLine(MyNumber);
    }
}

Когда это скомпилировано, результирующий код выглядит так

public class MyClass
{


    public void MyMethod()
    {
        Console.WriteLine(2);
    }
}

Он будет скомпилирован в IL, но вы поймете.

Это означает, что вы можете помечать вещи как константы, которые известны при компиляции и являются примитивными объектами C#, такими как string, int, decimal и т. Д.

К сожалению, readonly в настоящее время не разрешен для переменных. Однако есть разговоры о том, как сделать это возможным https://www.infoq.com/news/2017/04/CSharp-Readonly-Locals

  1. Вы не можете использовать const, Вы можете думать о const меньше как переменная, а больше как макрос, который заменяет все экземпляры значением во время компиляции. Может использоваться только со строками и примитивами.

  2. Вы можете использовать только readonly с полями, а не с локальными переменными. Может быть, это должно быть разрешено, но это не так.

Я понимаю, почему вы хотите что-то подобное, по сути, эквивалент const в JavaScript и TypeScript, или val в Котлине.

Увы, C# не имеет этой функциональности, и, к сожалению, const не работает так.

Вы могли бы сделать это:

namespace IAMAGoodDeveloper
{
    public static class Program
    {
        private static readonly int cert;

        static void Main(string[] args)
        {
            var myFactory = new MyFactory();
            var secretsProvider = myFactory.GenerateKeyProvider();
            cert = secretsProvider.GetKey("arg");
        }
    }
}

Когда я это делаю, я получаю ошибку: "Выражение, назначаемое сертификату, должно быть константой".

Игнорирование того, что вы хотите, и рассмотрение ограничений того, что C# предоставляет для значений const: const (C# Reference).

Константы могут быть числами, логическими значениями, строками или пустой ссылкой.

Я не знаю, что еще вам сказать, вы просто не можете использовать экземпляр объекта.

Теперь альтернативный способ создания более безопасного объекта только для чтения - это предоставление только интерфейса:

public class MyFactory
{
    public IKeyGen GenerateKeyProvider()
    {
        return new KeyGen();
    }

    public interface IKeyGen 
    {
      int GetKey(string arg);
    }

    private class KeyGen : IKeyGen
    {
        public int GetKey(string arg)
        {
            return 1;
        }
    }
}

Поскольку вы не включили какое-либо использование этого объекта, крайне сложно определить что-либо кроме того, что вы не хотите, чтобы сам объект изменялся.

Другие вопросы по тегам