2016-08-16 6 views
4



У меня есть очень простые методы побитового Оператора, который я хочу использовать так:
C# - Реферирование параметр «это ИНТ»

myInt.SetBit(int k, bool set) 

так, что он изменяет значение бита с индексом «к» к значение «установить» (0 или 1) Я сначала подумал сделать это так:

public static void SetBit(this int A, int k, bool set) { 
    if (set) A |= 1 << k; 
    else A &= ~(1 << k); 
} 

, но, конечно, это только изменяет внутреннее значение переменной «A», а не исходные переменные, так как целый ISN 'тип ссылки.
Я не могу использовать 'ref' вместе с 'this', поэтому я не знаю, как превратить это в ссылочный параметр.
У меня уже есть аналогичные методы для массивов Int, но они отлично работают, поскольку массив является ссылочным типом.

Я ищу способ сохранить этот удобный синтаксис для одиночных целых чисел, если он есть.

+1

Измените свою подпись с 'void' на' int' и верните новое значение. – Igor

ответ

1

Я предлагаю просто возвращение результат вместо того, чтобы пытаться изменить неизменное int:

// int instead of void 
    public static int SetBit(this int A, int k, bool set) { 
    return set ? (A | (1 << k)) : (A & (~(1 << k))); 
    } 

Так что вы можете сделать

int source = 12345; 
    int result = source.SetBit(3, true); 
+0

У меня было несколько ответов, объясняющих лучшее решение за очень короткое время. Я ставил этот вопрос как правильный ответ, потому что он был очень ясным и точным, а также оптимизированный однострочный синтаксис. Спасибо всем, кто нашел время ответить! – grr

5

Вы не должны относиться к нему как к ссылочному типу.

Сделайте свой метод возвращенным измененным значением и назначьте его обратно вашей переменной. Такой подход будет соответствовать неизменяемым типам. Рассмотрим пример String.Replace, он не изменяет строку на месте, вместо этого возвращает измененную копию.

public static int SetBit(this int A, int k, bool set) 
{ 
    if (set) A |= 1 << k; 
    else A &= ~(1 << k); 

    return A; 
} 
+0

Спасибо за очень быстрый ответ! Это имеет большой смысл, хотя он меняет синтаксис на 'myInt = myInt.SetBit (parameters)' вместо того, чтобы просто «myInt.SetBit (parameters)» работать сам по себе. Я надеялся сохранить простой синтаксис, но я решил, что это может быть необходимо, это действительно похоже на лучшее решение. – grr

0

Мне пришлось проверить это, потому что это выглядит немного странно. Разумеется, вы не можете написать метод расширения, используя ref.

See here, кто-то пробовал это.

4

Некоторые виды (например, int s) неизменны, это означает, что как только они будут установлены в значение, они не могут быть изменены снова. Вы заметите, что любой метод, работающий над int, вернет новый int вместо изменения значения данного значения.

Обновить код как это:

public static int SetBit(this int A, int k, bool set) { 
    if (set) A |= 1 << k; 
    else A &= ~(1 << k); 
    return A; 
} 

и использовать его как:

var x = 5; 
x = x.SetBit(1, true); 
+0

* Вы заметите, что любой метод, работающий над int, вернет новый int, а не изменит значение данного значения * - ну, кроме методов с параметрами 'ref int' ... – Rawling

+0

Er, nope. Как насчет 'x ++'? – DavidG

+0

x ++ - семантический сахар для x + = 1, который является семантическим сахаром для x = x + 1. – Glubus

0

Вы не можете смешивать this и ref в методах расширения.У вас есть много вариантов:

  1. возвращает результат от метода расширения (я предпочитаю этот вариант):

    public static int SetBit(this int A, int k, bool set) 
    { 
        if (set) A |= 1 << k; 
        else A &= ~(1 << k); 
    
        return A; 
    } 
    

    с помощью:

    int i = 3;  
    i = i.SetBit(1, false); 
    
  2. Используя метод с ref:

    public static void SetBitRef(ref int A, int k, bool set) 
    { 
        if (set) A |= 1 << k; 
        else A &= ~(1 << k); 
    } 
    

    с помощью:

    int i = 3; 
        IntExtensions.SetBitRef(ref i, 1, false); 
    
  3. Использование класса IntWrapper вместо междунар:

    class IntWrapper 
        { 
         public IntWrapper(int intValue) 
         { 
          Value = intValue; 
         } 
    
         public int Value { get; set; } 
        } 
    

    с ссылочного типа вы можете создать этот метод расширения:

    public static void SetBit(this IntWrapper A, int k, bool set) 
    { 
        int intValue = A.Value; 
    
        if (set) intValue |= 1 << k; 
        else intValue &= ~(1 << k); 
    
        A.Value = intValue; 
    } 
    

    с помощью:

    IntWrapper iw = new IntWrapper(3); 
    iw.SetBit(1, false);