Создание собственного класса int или string - PullRequest
2 голосов
/ 06 апреля 2010

Я разобрал .NET 'System' DLL и посмотрел на исходный код переменных классов (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());
}

Ответы [ 4 ]

7 голосов
/ 06 апреля 2010

Вы можете сделать это с помощью операторов перегрузки . Есть учебник по MSDN .

Допустим, вам нужен тип, который может быть либо строкой, либо целым числом (например, в любом из них в Haskell):

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
}
3 голосов
/ 06 апреля 2010

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

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

1 голос
/ 06 апреля 2010

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

Если вы хотите хранить другой тип данных, например комбинацию string и 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 может передаваться в отсортированные списки, поскольку он способен сравнивать себя с другим экземпляром и соответствующим образом «ранжировать» их.

1 голос
/ 06 апреля 2010

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

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

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());
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...