Создание собственного класса int или string

Я разобрал библиотеку .NET «System» и посмотрел исходный код для классов переменных (string, int, byte и т. Д.), Чтобы узнать, смогу ли я выяснить, как создать класс, который мог бы принимать значение. Я заметил, что класс «Int32» наследует следующее: IComparable, IFormattable, IConvertible, IComparable, IEquatable.

Классы String и Int32 не наследуются, и я не могу понять, что в этих унаследованных интерфейсах позволяет классам хранить значение. Я бы хотел что-то вроде этого:

public class MyVariable : //inherits here
{
     //Code in here that allows it to get/set the value
} 

public static class Main(string[] args)
{
     MyVariable a = "This is my own custom variable!";
     MyVariable b = 2976;

     if(a == "Hello") { }
     if(b = 10) { }
     Console.WriteLine(a.ToString());
     Console.WriteLine(a.ToString());
}

person afollestad    schedule 06.04.2010    source источник
comment
Я могу сделать эту компиляцию, но ... Почему?   -  person R. Martinho Fernandes    schedule 06.04.2010
comment
Кроме того, во втором случае отсутствует = (вероятно, должно быть b == 10)   -  person R. Martinho Fernandes    schedule 06.04.2010
comment
В строке 12 приведенного выше кода должно быть if(b == 10) {} вместо if(b = 10) {}?   -  person Siu Ching Pong -Asuka Kenji-    schedule 06.04.2010
comment
Приносим извинения за ошибки, это не предназначалось для компиляции. Просто быстрый пример, показывающий, что я бы хотел от него. Я нашел ответ внизу (операторы перегрузки).   -  person afollestad    schedule 06.04.2010
comment
Поскольку в комментариях есть ответы, которые вы назвали правильными, вы должны принять их как правильный ответ (щелкните галочку).   -  person Samuel Neff    schedule 05.06.2011


Ответы (4)


Это можно сделать с помощью операторов перегрузки. Существует руководство по MSDN.

Допустим, вам нужен тип, который может быть либо строкой, либо int (например, Либо):

public sealed class StringOrInt32
{
    private string stringValue;
    private int int32Value;
    private bool isString;

    public bool IsString { get { return isString; } }
    public bool IsInt32 { get { return !isString; } }

    public string StringValue
    {
        get
        {
            if(!isString) throw new InvalidOperationException();
            return stringValue;
        }
    }

    public int Int32Value
    {
        get
        {
            if(isString) throw new InvalidOperationException();
            return int32Value;
        }
    }

    public StringOrInt32(string value)
    {
        isString = true;
        stringValue = value;
    }

    public StringOrInt32(int value)
    {
        isString = false;
        int32Value = value;
    }

    // Allows writing this:
    // StringOrInt32 foo = "Hello world!";
    public static implicit operator StringOrInt32(string value)
    {
        return new MyVariable(value);
    }

    // Allows writing this:
    // StringOrInt32 foo = 42;
    public static implicit operator StringOrInt32(int value)
    {
        return new MyVariable(value);
    }

    // Allows writing this:
    // StringOrInt32 foo = "Hello world!;
    // string bar = (string)foo;
    // Though foo.StringValue directly would be better
    public static explicit operator string(StringOrInt32 value)
    {
        return value.StringValule;
    }

    // Allows writing this:
    // StringOrInt32 foo = 42;
    // int bar = (int)foo;
    // Though foo.Int32Value directly would be better
    public static explicit operator int(StringOrInt32 value)
    {
        return value.Int32Value;
    }

    public static bool operator==(StringOrInt32 left, StringOrInt32 right)
    {
        if(left.IsString != right.IsString)
            return false;
        if(left.IsString)
            return left.StringValue == right.StringValue;
        else
            return left.Int32Value == right.Int32Value;
    }

    public static bool operator!=(StringOrInt32 left, StringOrInt32 right)
    {
        return !(left == right)
    }

    // Don't forget to override object.Equals(), object.GetHashCode(),
    // and consider implementing IEquatable<StringOrInt32>
    // Also, null checks, etc
}
person R. Martinho Fernandes    schedule 06.04.2010
comment
Спасибо! Как и один из других ответов, это именно то, что я искал. - person afollestad; 06.04.2010

Встроенные типы в C # обрабатываются «специально», так как буквальное значение 1234 в коде определяется как имеющее тип System.Int32, а буквальное значение "some string" определяется как имеющее тип System.String.

Итак, для поддержки того типа кода, который вам нужен, вам нужно будет предоставить операторы преобразования, которые могут преобразовывать из int и string (и всего остального) в ваш тип. Изучите тему операторы преобразования в MSDN.

person Dean Harding    schedule 06.04.2010

Обычно вы хотите создать новый тип для хранения нового представления данных. В приведенном выше примере вы используете MyVariable для хранения строк - то, что строковый тип уже хорошо умеет делать.

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

public class MyVariable
{
    public string Name { get; set; }
    public int Age { get; set; }
} 

Потом:

MyVariable personOne = new MyVariable { Name = "John", Age = 34 };
MyVariable personTwo = new MyVariable { Name = "Joe", Age = 312 };

Такие интерфейсы, как IComparable и IFormattable, позволяют использовать ваш новый тип определенными способами, например, IComparable может быть передан в отсортированные списки, поскольку он способен сравнивать себя с другим экземпляром и соответственно «ранжировать» их.

person Michael Shimmins    schedule 06.04.2010

"int" и "string" являются встроенными типами. Вы не сможете создать такой же, как он, без видимых полей. Однако вы можете сделать что-то, что выглядит и ведет себя почти так же, как встроенный тип.

Лучший пример - Nullable<T>. Это обеспечивает версию всех типов значений, допускающую значение NULL, и может быть назначен так же, как он встроен:

int? x = 0;
int? y = null;

Это работает так: Nullable<T> переопределяет явное и неявное приведение типов. Таким образом, вы можете назначить встроенный тип, например int, пользовательскому Nullable<int>, а код внутри Nullable<int>.op_Implicit прозрачно обрабатывает преобразование.

Вот полный пример:

public struct MyVariable
{
    private int _intValue;
    private string _stringValue;

    public override bool Equals(object obj)
    {
        if (!(obj is MyVariable))
        {
            return false;
        }
        var y = (MyVariable) obj;
        return _stringValue == y._stringValue && _intValue == y._intValue;
    }

    public override int GetHashCode()
    {
        return (_stringValue ?? _intValue.ToString()).GetHashCode();
    }

    public override string ToString()
    {
        return _stringValue ?? _intValue.ToString();
    }

    public static implicit operator MyVariable(string value)
    {
        return new MyVariable { _stringValue = value };
    }

    public static implicit operator MyVariable(int value)
    {
        return new MyVariable { _intValue = value };
    }

    public static bool operator==(MyVariable variable, string value)
    {
        return variable._stringValue == value;
    }

    public static bool operator ==(MyVariable variable, int value)
    {
        return variable._intValue == value;
    }

    public static bool operator !=(MyVariable variable, string value)
    {
        return variable._stringValue == value;
    }

    public static bool operator !=(MyVariable variable, int value)
    {
        return variable._intValue == value;
    }

    public static void Test()
    {
        MyVariable a = "This is my own custom variable!";
        MyVariable b = 2976;

        if (a == "Hello") { }
        if (b == 10) { }
        Console.WriteLine(a.ToString());
        Console.WriteLine(a.ToString());
    }
}
person Samuel Neff    schedule 06.04.2010
comment
Nullable на самом деле имеет некоторую дополнительную магию за приведениями, которые вы не можете эмулировать в C #: операторы поднятых типов. - person R. Martinho Fernandes; 06.04.2010
comment
Спасибо! Это именно то, что я искал. - person afollestad; 06.04.2010