Làm cách nào để cung cấp hỗ trợ truyền tùy chỉnh cho lớp của tôi?


102

Làm cách nào để hỗ trợ truyền lớp của tôi sang các loại khác? Ví dụ: nếu tôi có triển khai quản lý a của riêng mình byte[]và tôi muốn cho phép mọi người chuyển lớp của tôi thành a byte[], điều này sẽ chỉ trả về thành viên private, tôi sẽ làm điều này như thế nào?

Có phải thông lệ là để họ cũng truyền dữ liệu này thành một chuỗi hay tôi chỉ nên ghi đè ToString()(hoặc cả hai)?

Câu trả lời:


112

Bạn sẽ cần ghi đè toán tử chuyển đổi, sử dụng một trong hai implicithoặc explicittùy thuộc vào việc bạn muốn người dùng phải truyền nó hay bạn muốn nó diễn ra tự động. Nói chung, một hướng sẽ luôn hoạt động, đó là nơi bạn sử dụng implicit, và hướng khác đôi khi có thể thất bại, đó là nơi bạn sử dụng explicit.

Cú pháp như sau:

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

hoặc là

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

Đối với ví dụ của bạn, hãy nói từ Loại tùy chỉnh của bạn ( MyType-> byte[]sẽ luôn hoạt động):

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

hoặc là

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

Bạn có thể khai báo toán tử chuyển đổi trên lớp của mình bằng cách sử dụng từ khóa explicithoặc implicit.

Theo nguyên tắc chung, bạn chỉ nên cung cấp implicittoán tử chuyển đổi khi chuyển đổi không thể không thành công. Sử dụng explicittoán tử chuyển đổi khi chuyển đổi có thể không thành công.

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;
    }
}

Việc sử dụng explicitcó nghĩa là người dùng trong lớp của bạn sẽ cần thực hiện chuyển đổi rõ ràng:

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;

Sử dụng implicitcó nghĩa là người dùng trong lớp của bạn không cần thực hiện chuyển đổi rõ ràng, tất cả đều diễn ra minh bạch:

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

Tôi thích có một số phương thức sẽ làm điều đó hơn là nạp chồng toán tử ép kiểu.

Xem c # rõ ràng và ẩn nhưng lưu ý rằng từ ví dụ đó, sử dụng phương thức rõ ràng, nếu bạn làm:

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

Sau đó, mọi thứ đều ổn; tuy nhiên, nếu bạn sử dụng:

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

Bây giờ bạn sẽ nhận được một InvalidCastException vì chuỗi không thể được truyền cho Vai trò, tại sao, trình biên dịch chỉ tìm kiếm các kiểu ẩn / rõ ràng tại thời điểm biên dịch dựa trên kiểu đã biên dịch của chúng. Trong trường hợp này, trình biên dịch coi tên là một đối tượng chứ không phải là chuỗi và do đó không sử dụng toán tử nạp chồng của Vai trò.


Nhìn vào ví dụ mà bạn đã liên kết, nó dường như tạo ra phiên bản mới của đối tượng trên mỗi lần truyền. Bất kỳ ý tưởng làm thế nào để chỉ thực hiện loại hoạt động get / set trên một thành viên hiện tại của lớp?
esac 10/09/09

3

Để hỗ trợ ép kiểu tùy chỉnh, bạn cần cung cấp toán tử ép kiểu (rõ ràng hoặc ngầm định). Ví dụ sau về lớp EncodedString là cách triển khai chuỗi đơn giản với mã hóa tùy chỉnh (có thể hữu ích nếu bạn phải xử lý các chuỗi khổng lồ và gặp phải vấn đề tiêu thụ bộ nhớ vì chuỗi .Net là Unicode - mỗi ký tự chiếm 2 byte bộ nhớ - và Chuỗi mã hóa có thể mất 1 byte trên mỗi ký tự).

EncodedString có thể được chuyển đổi thành byte [] và thành System.String. Nhận xét trong mã làm sáng tỏ một số điều và cũng giải thích một ví dụ khi chuyển đổi ngầm định có thể nguy hiểm.

Thông thường bạn cần một lý do chính đáng để khai báo bất kỳ toán tử chuyển đổi nào ngay từ đầu bởi vì.

Đọc thêm có sẵn trên 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();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.