Как создать класс значений, например byte

в C# внутренне байт определяется как что-то вроде (извините, у меня нет реального кода, это мой вопрос):

public class byte {
  int bytValue = 0;

  get {
    return bytValue;
  }

  set {
    if (value < 0 || value > 255) {
      throw;
    }
    
    bytValue = value;
  }
}

Теперь предположим, что я хочу создать такой класс и назвать его bytePlus, который будет ограничен диапазоном от 0 до 512. Как мне создать класс «Значение», при вызове которого он дает значение?

Я мог бы настаивать [я не хочу перегружать byte, я действительно использую byte в качестве примера, я собираюсь создать другой тип класса типа «значение»]

Пример:

public class bytePlus {
...
}

Когда я делаю что-то вроде этого:

public bytePlus MyValue = 4;

Я хочу, чтобы MyValue действовал как значение. Потому что свойство «по умолчанию» должно возвращать значение. Но я хочу добавить и другие свойства (это самая простая часть).

Как определить такой класс?

Я погуглил, чтобы найти ответ... безуспешно

ПЫТАТЬСЯ:

    class BytePlus {
        private uint _value;
        
        // User-defined conversion from Digit to double 
        public static implicit operator uint(BytePlus d) {
            return d._value;
        }
    }

когда я пытаюсь:

bytePlus rrr = new bytePlus();
rrr = rrr + 1;

не работает, добавить нельзя. «невозможно преобразовать uint в bytePlus()»

Моя конечная цель состоит в том, что к «значению» прикреплено строковое свойство, которое должно оставаться со значением из класса. Когда «реальное» значение обновляется, строковое значение также необходимо обновить, поскольку оно представляет собой своего рода crc указанного значения.

Предложение @shingo было верным, но я не смог его понять, потому что требовалось еще немного кода.

здесь код на основе MakePeaceGreatAgain принял ответ

public class BytePlus {
    private uint uintValue = 0;

    public BytePlus() {
        //
    }

    public BytePlus(uint b) {
        this.Value = b;
    }

    public uint Value {
        get {
            return uintValue;
        }
        set {
            //here I can add my code...
            uintValue = value;
        }
    }

    //here I can add my other properties

    public static implicit operator uint(BytePlus d) => d.Value;
    public static implicit operator BytePlus(uint b) => new BytePlus(b);
}

тогда я делаю:

BytePlus hex32 = 4;
hex32++;

Не уверен, что понимаю, что вы имеете в виду. Но если поставить struct вместо class, это станет типом значения.

wohlstad 20.08.2024 14:15

Байт - это отдельный тип данных, он соответствует 1...байту памяти, не имеет внутреннего хранилища с int (а это 4 байта)

Guru Stron 20.08.2024 14:16
bytePlus MyValue = 4; похоже, что ОП хочет неявного, определяемого пользователем приведения. См. Learn.microsoft.com/dotnet/csharp/language-reference/operato‌​rs/…
MakePeaceGreatAgain 20.08.2024 14:19

@wohlstad, создав структуру, не позволит мне добавлять свойства.

Sigma3Wolf 20.08.2024 15:37

@Guru Строн: да, ты прав. Как я уже сказал, байт — это всего лишь пример, для моего примера мне следовало выбрать int или строку. Я понимаю двоичный код и то, как он формирует максимальное значение каждого типа значения.

Sigma3Wolf 20.08.2024 15:41

@MakePeaceGreatAgain: я знаю, что пример неверен, как указано в моем вопросе (не нашел лучшего объяснения). Я не пытаюсь перегрузить байт, а создать новый определенный класс типа «значение» со своим собственным атрибутом и методом. .

Sigma3Wolf 20.08.2024 15:46

@shingo: вроде бы так, но позвольте мне проверить, все ли получилось. если это тот же вопрос, каков «правильный» процесс, следует ли мне закрыть вопрос или сделать его связанным с этим другим вопросом?

Sigma3Wolf 20.08.2024 15:47

@ Sigma3Wolf Я понял твою точку зрения. Проблема просто в том, что как только вы конвертируете свой суперкласс обратно в байт, вся дополнительная информация теряется, поскольку байт (или любой другой тип, который вы на самом деле оборачиваете) не имеет ни малейшего понятия об этой дополнительной информации. Это будет работать только в том случае, если ваши два типа информационно схожи, то есть представляют одни и те же данные. Тогда ваш приведение по сути представляет собой своего рода сопоставление между двумя типами.

MakePeaceGreatAgain 20.08.2024 15:49

@MakePeaceGreatAgain: я не собираюсь конвертировать обратно во что-либо еще, это новое определение класса значений. Тем временем я увидел, что кто-то приписал себе «ответ», что он/она/они считают это правильным, поэтому я оценю ответ, но пока он не соответствует моим потребностям.

Sigma3Wolf 20.08.2024 15:59

пока вы на самом деле просто приводите завернутый тип (например, byte) в свою обертку (BytePlus), все в порядке. Однако, если вы намерены поступить иначе, вы можете потерять информацию.

MakePeaceGreatAgain 20.08.2024 16:17
struct типы могут иметь свойства.
Joel Coehoorn 20.08.2024 16:21

ваше редактирование превращает ваш вопрос в нечто совершенно новое. Теперь вы спрашиваете: как я могу перегрузить оператор (например, +) для своего типа?

MakePeaceGreatAgain 20.08.2024 16:21

@MakePeaceGreatAgain Я понимаю твою точку зрения. Фоновое значение — это uint, и когда я отправляю его обратно пользователю, я использую uint. Никакой потери информации не будет. К «значению» прикреплено строковое свойство, которое должно соответствовать значению из класса. Когда «реальное» значение обновляется, строковое значение также необходимо обновить, поскольку оно представляет собой CRC указанного значения.

Sigma3Wolf 20.08.2024 16:24

«Ваше редактирование превращает ваш вопрос во что-то…» (опять!) Постарайтесь подумать о том, что вы хотите спросить, и не скрывайте информацию в своем вопросе.

Luuk 20.08.2024 16:28

@MakePeaceGreatAgain: совсем нет. Я знаю, что это сбивает с толку, потому что кто-то добавил и пометил что-то как ответ, а теперь это удалили. Но я попытался заставить его работать с «предложенным» ответом, но в конце концов мне это не удалось, и «ответ» был удален. код, который я вставил в свой вопрос, показывает что-то, что «выглядит» многообещающе как ответ от синго. Мой первоначальный вопрос: мне нужен класс «ценности». по определению я могу сделать класс значений: MyVar++; но внутри мне нужно контролировать строковое значение, прикрепленное к этому «реальному значению»

Sigma3Wolf 20.08.2024 16:28

ни один ответ вообще кем-то не был удален, я просто удалил свой, потому что он уже не вписывался в ваши правки. И предлагаемый дубликат имеет точно такую ​​же проблему, он не соответствует вашим изменениям. Опять же: вы спросили, как преобразовать свой тип в другой, на что ответили я и дурак. После этого вы спросили: как я могу изменить то, что делает +, это совсем другой вопрос. Пожалуйста, будьте как можно более конкретны в отношении того, чего вы действительно хотите достичь, а не рассказывайте о том, что, по вашему мнению, является решением.

MakePeaceGreatAgain 20.08.2024 16:31

@Luuk, мой вопрос остался прежним. «Как мне создать «класс значений», который я могу использовать как значение, но с добавленным свойством (в данном случае строкой).

Sigma3Wolf 20.08.2024 16:31

Почему бы вам просто не добавить в свой класс какую-нибудь Add-функцию: public void Add(uint amount) { this.Value += amount; }.

MakePeaceGreatAgain 20.08.2024 16:33

@MakePeaceGreatAgain никоим образом не хочу тебя обидеть. возможно мы не понимаем друг друга, возможно мой вопрос неоднозначен. Я ценю весь ваш вклад. Мой вопрос не изменился, я просто плыл по течению предложений и пытался понять, что они означают. Если бы я знал ответ, я бы не задавал вопрос. если кто-то что-то предлагает, это должно быть что-то, чего я не знаю. поэтому мое понимание этого несколько ограничено. В своем редактировании (вопросе) я поместил то, что пробовал, а что НЕ сработало, чтобы вы могли понять, что я пытаюсь. извините за путаницу

Sigma3Wolf 20.08.2024 16:35

@MakePeaceGreatAgain Я мог бы добавить Add(), но тогда мне придется повторить весь алфавит арифметических операций. Модуль, вычитание, деление и все такое. Мне нужен класс uint, который действует как uint, но с совершенно новым набором функций и свойств внутри. Я не знаю, как это сделать

Sigma3Wolf 20.08.2024 16:37

вам все равно нужно это сделать, потому что понятие + и * просто не применимо ко всем видам того, что вы считаете ценностью. Например, хотя string имеет перегрузку для +, что должно вернуть "MyString" * "MyOtherString"? Нет такого понятия, как перемножение двух строк. Короче говоря, вам нужно предоставить эти функции самостоятельно.

MakePeaceGreatAgain 20.08.2024 16:45

В настоящее время в вашем вопросе нет кода того, как вы ожидаете, что это строковое свойство будет работать. Я бы предположил, что это, вероятно, должен быть тип значения и неизменяемый - чтобы, когда вы это сделаете, он создавал новое значение, а не изменял существующее. Как уже говорили другие, это означает, что вам, вероятно, нужен myValue + 1 и без каких-либо сеттеров... но трудно догадаться, как помочь, когда требования расплывчаты.

Jon Skeet 20.08.2024 16:51

@Jon Skeet: потому что проблема не в свойстве строки, а в том, как я могу перехватить операцию, выполняемую над значением. Теперь я понял, что мой вопрос был недостаточно ясен, но трудно объяснить концепцию, основанную на решении, когда у вас нет решения. Я не знал, что нужно перегрузить оператора, MakePeaceGreatAgain открыл мне глаза

Sigma3Wolf 20.08.2024 17:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
23
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По сути, вы можете добавить неявное приведение к вашему BytePlus-типу, что сделает возможным следующее:

BytePlus MyValue = 4;

Другой способ также работает:

byte b = new BytePlus(4);

Итак, вам нужен operator для конвертации:

class BytePlus
{
    public BytePlus(byte b)
    {
        this.Value = b;
    }
    public byte Value { ... }
    
    public static implicit operator byte(BytePlus d) => d.Value;
    public static implicit operator BytePlus(byte b) => new BytePlus(b);
}

Однако имейте в виду, что неявное приведение подразумевает преобразование без потерь. Таким образом, при преобразовании byte в BytePlus вы, по сути, добавляете информацию, и это нормально. Однако другой путь недопустим, поскольку преобразование из BytePlus в byte может привести к потере информации (у byte нет знаний об участниках вашего BytePlus-класса). В этих сценариях обычно лучше использовать оператор explicit, что по сути означает: «при этом приведении может произойти потеря информации, но меня это устраивает».

См. также документацию по пользовательским приведениям: https://learn.microsoft.com/dotnet/csharp/language-reference/operators/user-defined-conversion-operators

Если вам также нужен какой-либо оператор для вашего типа, что означает, что вы хотите предоставить, например, +и -, вы можете добавить это, выполнив следующие действия:

class BytePlus
{
    public static BytePlus operator + (BytePlus b, byte amount) => new BytePlus(b.Value + amount);
    public static BytePlus operator - (BytePlus b, byte amount) => new BytePlus(b.Value - amount);
}

вы также можете определить explicit operator для первого случая, чтобы устранить «безубыточность».

Ivan Petrov 20.08.2024 15:12

это просто невозможно, поскольку два ваших типа ничего не знают друг о друге. Это означает, что вы можете конвертировать каждый long в int и обратно, что просто невозможно. Создание оператора explicit просто делает это видимым для ваших пользователей.

MakePeaceGreatAgain 20.08.2024 15:26

почему это невозможно? Именно в этом его цель — видимость и знания, которые он может дать. Так и должно быть, когда есть «потери», т. е. long больше, чем int.

Ivan Petrov 20.08.2024 16:08

@MakePeaceGreatAgain: мне нравится этот код. не знаю, как адаптироваться к моим потребностям... Могу ли я использовать MyVar++; ?

Sigma3Wolf 20.08.2024 16:43

@ Sigma3Wolf, как уже упоминалось в другом моем комментарии к вопросу: только если вы сами предоставите оператор ++. Поэтому перегрузите и этот оператор.

MakePeaceGreatAgain 20.08.2024 16:46

@MakePeaceGreatAgain на данный момент, из-за отсутствия у меня знаний в таких вещах... Я не уверен, что понимаю, почему это работает, но ваш код великолепен и работает. Я приму ваш ответ и отредактирую вопрос, чтобы показать, что я в итоге сделал.

Sigma3Wolf 20.08.2024 16:55

@MakePeaceGreatAgain: я не уверен, что делает следующая строка: общедоступный статический неявный оператор BytePlus(uint b) => new BytePlus(b); Мне придется кое-что протестировать. но это работает, и я буду работать над этим, чтобы лучше понять это. Большое спасибо !!!

Sigma3Wolf 20.08.2024 17:12

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