в 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++;
Байт - это отдельный тип данных, он соответствует 1...байту памяти, не имеет внутреннего хранилища с int (а это 4 байта)
bytePlus MyValue = 4;
похоже, что ОП хочет неявного, определяемого пользователем приведения. См. Learn.microsoft.com/dotnet/csharp/language-reference/operators/…@wohlstad, создав структуру, не позволит мне добавлять свойства.
@Guru Строн: да, ты прав. Как я уже сказал, байт — это всего лишь пример, для моего примера мне следовало выбрать int или строку. Я понимаю двоичный код и то, как он формирует максимальное значение каждого типа значения.
@MakePeaceGreatAgain: я знаю, что пример неверен, как указано в моем вопросе (не нашел лучшего объяснения). Я не пытаюсь перегрузить байт, а создать новый определенный класс типа «значение» со своим собственным атрибутом и методом. .
@shingo: вроде бы так, но позвольте мне проверить, все ли получилось. если это тот же вопрос, каков «правильный» процесс, следует ли мне закрыть вопрос или сделать его связанным с этим другим вопросом?
@ Sigma3Wolf Я понял твою точку зрения. Проблема просто в том, что как только вы конвертируете свой суперкласс обратно в байт, вся дополнительная информация теряется, поскольку байт (или любой другой тип, который вы на самом деле оборачиваете) не имеет ни малейшего понятия об этой дополнительной информации. Это будет работать только в том случае, если ваши два типа информационно схожи, то есть представляют одни и те же данные. Тогда ваш приведение по сути представляет собой своего рода сопоставление между двумя типами.
@MakePeaceGreatAgain: я не собираюсь конвертировать обратно во что-либо еще, это новое определение класса значений. Тем временем я увидел, что кто-то приписал себе «ответ», что он/она/они считают это правильным, поэтому я оценю ответ, но пока он не соответствует моим потребностям.
пока вы на самом деле просто приводите завернутый тип (например, byte
) в свою обертку (BytePlus
), все в порядке. Однако, если вы намерены поступить иначе, вы можете потерять информацию.
struct
типы могут иметь свойства.
ваше редактирование превращает ваш вопрос в нечто совершенно новое. Теперь вы спрашиваете: как я могу перегрузить оператор (например, +
) для своего типа?
@MakePeaceGreatAgain Я понимаю твою точку зрения. Фоновое значение — это uint, и когда я отправляю его обратно пользователю, я использую uint. Никакой потери информации не будет. К «значению» прикреплено строковое свойство, которое должно соответствовать значению из класса. Когда «реальное» значение обновляется, строковое значение также необходимо обновить, поскольку оно представляет собой CRC указанного значения.
«Ваше редактирование превращает ваш вопрос во что-то…» (опять!) Постарайтесь подумать о том, что вы хотите спросить, и не скрывайте информацию в своем вопросе.
@MakePeaceGreatAgain: совсем нет. Я знаю, что это сбивает с толку, потому что кто-то добавил и пометил что-то как ответ, а теперь это удалили. Но я попытался заставить его работать с «предложенным» ответом, но в конце концов мне это не удалось, и «ответ» был удален. код, который я вставил в свой вопрос, показывает что-то, что «выглядит» многообещающе как ответ от синго. Мой первоначальный вопрос: мне нужен класс «ценности». по определению я могу сделать класс значений: MyVar++; но внутри мне нужно контролировать строковое значение, прикрепленное к этому «реальному значению»
ни один ответ вообще кем-то не был удален, я просто удалил свой, потому что он уже не вписывался в ваши правки. И предлагаемый дубликат имеет точно такую же проблему, он не соответствует вашим изменениям. Опять же: вы спросили, как преобразовать свой тип в другой, на что ответили я и дурак. После этого вы спросили: как я могу изменить то, что делает +
, это совсем другой вопрос. Пожалуйста, будьте как можно более конкретны в отношении того, чего вы действительно хотите достичь, а не рассказывайте о том, что, по вашему мнению, является решением.
@Luuk, мой вопрос остался прежним. «Как мне создать «класс значений», который я могу использовать как значение, но с добавленным свойством (в данном случае строкой).
Почему бы вам просто не добавить в свой класс какую-нибудь Add
-функцию: public void Add(uint amount) { this.Value += amount; }
.
@MakePeaceGreatAgain никоим образом не хочу тебя обидеть. возможно мы не понимаем друг друга, возможно мой вопрос неоднозначен. Я ценю весь ваш вклад. Мой вопрос не изменился, я просто плыл по течению предложений и пытался понять, что они означают. Если бы я знал ответ, я бы не задавал вопрос. если кто-то что-то предлагает, это должно быть что-то, чего я не знаю. поэтому мое понимание этого несколько ограничено. В своем редактировании (вопросе) я поместил то, что пробовал, а что НЕ сработало, чтобы вы могли понять, что я пытаюсь. извините за путаницу
@MakePeaceGreatAgain Я мог бы добавить Add(), но тогда мне придется повторить весь алфавит арифметических операций. Модуль, вычитание, деление и все такое. Мне нужен класс uint, который действует как uint, но с совершенно новым набором функций и свойств внутри. Я не знаю, как это сделать
вам все равно нужно это сделать, потому что понятие +
и *
просто не применимо ко всем видам того, что вы считаете ценностью. Например, хотя string
имеет перегрузку для +
, что должно вернуть "MyString" * "MyOtherString"
? Нет такого понятия, как перемножение двух строк. Короче говоря, вам нужно предоставить эти функции самостоятельно.
В настоящее время в вашем вопросе нет кода того, как вы ожидаете, что это строковое свойство будет работать. Я бы предположил, что это, вероятно, должен быть тип значения и неизменяемый - чтобы, когда вы это сделаете, он создавал новое значение, а не изменял существующее. Как уже говорили другие, это означает, что вам, вероятно, нужен myValue + 1
и без каких-либо сеттеров... но трудно догадаться, как помочь, когда требования расплывчаты.
@Jon Skeet: потому что проблема не в свойстве строки, а в том, как я могу перехватить операцию, выполняемую над значением. Теперь я понял, что мой вопрос был недостаточно ясен, но трудно объяснить концепцию, основанную на решении, когда у вас нет решения. Я не знал, что нужно перегрузить оператора, MakePeaceGreatAgain открыл мне глаза
По сути, вы можете добавить неявное приведение к вашему 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
для первого случая, чтобы устранить «безубыточность».
это просто невозможно, поскольку два ваших типа ничего не знают друг о друге. Это означает, что вы можете конвертировать каждый long
в int
и обратно, что просто невозможно. Создание оператора explicit
просто делает это видимым для ваших пользователей.
почему это невозможно? Именно в этом его цель — видимость и знания, которые он может дать. Так и должно быть, когда есть «потери», т. е. long больше, чем int.
@MakePeaceGreatAgain: мне нравится этот код. не знаю, как адаптироваться к моим потребностям... Могу ли я использовать MyVar++; ?
@ Sigma3Wolf, как уже упоминалось в другом моем комментарии к вопросу: только если вы сами предоставите оператор ++
. Поэтому перегрузите и этот оператор.
@MakePeaceGreatAgain на данный момент, из-за отсутствия у меня знаний в таких вещах... Я не уверен, что понимаю, почему это работает, но ваш код великолепен и работает. Я приму ваш ответ и отредактирую вопрос, чтобы показать, что я в итоге сделал.
@MakePeaceGreatAgain: я не уверен, что делает следующая строка: общедоступный статический неявный оператор BytePlus(uint b) => new BytePlus(b); Мне придется кое-что протестировать. но это работает, и я буду работать над этим, чтобы лучше понять это. Большое спасибо !!!
Не уверен, что понимаю, что вы имеете в виду. Но если поставить
struct
вместоclass
, это станет типом значения.