Як мені забезпечити користувальницьку підтримку для мого класу?


103

Як я можу надати підтримку для того, щоб передати свій клас іншим типам? Наприклад, якщо я маю власну реалізацію управління A byte[], і я хочу дозволити людям передати моєму класу а byte[], який просто поверне приватного члена, як би я це зробив?

Чи загальноприйнята практика дозволяти їм також кидати це на рядок, або я повинен просто замінити ToString()(або обидва)?

Відповіді:


113

Вам потрібно буде переоперувати оператора перетворення, використовуючи implicitабо explicitзалежно від того, чи потрібно, щоб користувачі мали це зробити, чи ви хочете, щоб це відбувалося автоматично. Як правило, один напрямок завжди буде працювати, саме там ви використовуєте implicit, а інший напрямок іноді може вийти з ладу, саме там ви використовуєте explicit.

Синтаксис такий:

public static implicit operator dbInt64(Byte x)
{
    return new dbInt64(x);
}

або

public static explicit operator Int64(dbInt64 x)
{
    if (!x.defined)
        throw new DataValueNullException();
    return x.iVal;
}

Для прикладу скажіть зі свого власного типу ( MyType-> byte[]завжди буде працювати):

public static implicit operator byte[] (MyType x)
{
    byte[] ba = // put code here to convert x into a byte[]
    return ba;
}

або

public static explicit operator MyType(byte[] x)
{
    if (!CanConvert)
        throw new DataValueNullException();

    // Factory to convert byte[] x into MyType
    MyType mt = MyType.Factory(x);
    return mt;
}

36

Ви можете оголосити операторів конверсій у своєму класі, використовуючи explicitабо implicitключові слова, або .

Як загальне правило, ви повинні надавати implicitоператорів конверсії лише тоді, коли конверсія не може бути завершена. Використовуйте explicitоператори перетворення, коли конверсія може бути невдалою.

public class MyClass
{
    private byte[] _bytes;

    // change explicit to implicit depending on what you need
    public static explicit operator MyClass(byte[] b)
    {
        MyClass m = new MyClass();
        m._bytes = b;
        return m;
    }

    // change explicit to implicit depending on what you need
    public static explicit operator byte[](MyClass m)
    {
        return m._bytes;
    }
}

Використання explicitозначає, що користувачам вашого класу потрібно буде зробити явну конверсію:

byte[] foo = new byte[] { 1, 2, 3, 4, 5 };
// explicitly convert foo into an instance of MyClass...
MyClass bar = (MyClass)foo;
// explicitly convert bar into a new byte[] array...
byte[] baz = (byte[])bar;

Використовуючи implicitозначає, що користувачам вашого класу не потрібно здійснювати явну конверсію, все відбувається прозоро:

byte[] foo = new byte[] { 1, 2, 3, 4, 5 };
// imlpicitly convert foo into an instance of MyClass...
MyClass bar = foo;
// implicitly convert bar into a new byte[] array...
byte[] baz = bar;

6

Я вважаю за краще мати якийсь метод, який буде робити це, а не перевантажувати оператор литих.

Дивіться явний та неявний c #, але зауважте, що з цього прикладу, використовуючи метод явного, якщо ви робите:

string name = "Test";
Role role = (Role) name;

Тоді все добре; однак, якщо ви використовуєте:

object name = "Test";
Role role = (Role) name;

Тепер ви отримаєте InvalidCastException, тому що рядок не можна передавати в роль, тому компілятор шукає лише неявні / явні касти під час компіляції на основі їх типу компіляції. У цьому випадку компілятор бачить ім'я як об'єкт, а не рядок, і тому не використовує перевантажений оператор Role.


Дивлячись на приклад, з яким ви пов'язуєтесь, здається, створюється новий екземпляр об'єкта в кожному складі. Будь-яка ідея, як просто зробити / встановити тип операцій на поточному члені класу?
esac

3

Для підтримки користувальницької ролі вам потрібно надати операторів литих (явних або неявних). Наступний приклад класу EncodedString - це спрощена реалізація рядка з користувацьким кодуванням (може бути корисним, якщо вам доведеться обробити величезні величезні рядки і зіткнутися з проблемами споживання пам'яті, оскільки. Net рядки Unicode - кожен символ займає 2 байти пам'яті - і EncodedString може приймати 1 байт на char).

EncodedString може бути перетворений у байт [] та в System.String. Коментарі в коді проливають трохи світла, а також пояснюють приклад, коли неявна конверсія може бути небезпечною.

Зазвичай вам потрібна дуже вагома причина, щоб оголосити будь-яких операторів конверсії в першу чергу, оскільки.

Подальше читання доступне на MSDN .

class Program
{
    class EncodedString
    {
        readonly byte[] _data;
        public readonly Encoding Encoding;

        public EncodedString(byte[] data, Encoding encoding)
        {
            _data = data;
            Encoding = encoding;
        }

        public static EncodedString FromString(string str, Encoding encoding)
        {
            return new EncodedString(encoding.GetBytes(str), encoding);
        }

        // Will make assumption about encoding - should be marked as explicit (in fact, I wouldn't recommend having this conversion at all!)
        public static explicit operator EncodedString(byte[] data)
        {
            return new EncodedString(data, Encoding.Default);
        }

        // Enough information for conversion - can make it implicit
        public static implicit operator byte[](EncodedString obj)
        {
            return obj._data;
        }

        // Strings in .Net are unicode so we make no assumptions here - implicit
        public static implicit operator EncodedString(string text)
        {
            var encoding = Encoding.Unicode;
            return new EncodedString(encoding.GetBytes(text), encoding);
        }

        // We have all the information for conversion here - implicit is OK
        public static implicit operator string(EncodedString obj)
        {
            return obj.Encoding.GetString(obj._data);
        }
    }

    static void Print(EncodedString format, params object[] args)
    {
        // Implicit conversion EncodedString --> string
        Console.WriteLine(format, args);
    }

    static void Main(string[] args)
    {
        // Text containing russian letters - needs care with Encoding!
        var text = "Привет, {0}!";

        // Implicit conversion string --> EncodedString
        Print(text, "world");

        // Create EncodedString from System.String but use UTF8 which takes 1 byte per char for simple English text
        var encodedStr = EncodedString.FromString(text, Encoding.UTF8);
        var fileName = Path.GetTempFileName();

        // Implicit conversion EncodedString --> byte[]
        File.WriteAllBytes(fileName, encodedStr);

        // Explicit conversion byte[] --> EncodedString
        // Prints *wrong* text because default encoding in conversion does not match actual encoding of the string
        // That's the reason I don't recommend to have this conversion!
        Print((EncodedString)File.ReadAllBytes(fileName), "StackOverflow.com");

        // Not a conversion at all. EncodingString is instantiated explicitly
        // Prints *correct* text because encoding is specified explicitly
        Print(new EncodedString(File.ReadAllBytes(fileName), Encoding.UTF8), "StackOverflow.com");

        Console.WriteLine("Press ENTER to finish");
        Console.ReadLine();
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.