내 수업에 대한 사용자 지정 캐스트 지원을 제공하려면 어떻게해야합니까?


103

내 클래스를 다른 유형으로 캐스팅하기위한 지원을 제공하려면 어떻게해야합니까? 예를 들어,을 관리하는 자체 구현이 byte[]있고 사람들이 내 클래스를으로 캐스트 할 수 있도록 byte[]하여 private 멤버를 반환하려면 어떻게해야합니까?

그들이 이것을 문자열로 캐스트하도록하는 것이 일반적인 관행입니까, 아니면 그냥 오버라이드 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;

이제 문자열을 Role로 캐스트 할 수 없기 때문에 InvalidCastException이 발생합니다. 왜 컴파일러는 컴파일 된 유형을 기반으로 컴파일 타임에 암시 적 / 명시 적 캐스트를 찾습니다. 이 경우 컴파일러는 이름을 문자열이 아닌 객체로 간주하므로 Role의 오버로드 된 연산자를 사용하지 않습니다.


연결 한 예제를 보면 모든 캐스트에서 개체의 새 인스턴스를 만드는 것 같습니다. 클래스의 현재 멤버에 대해 작업 유형을 가져 오거나 설정하는 방법에 대한 아이디어가 있습니까?
esac

3

커스텀 캐스트 지원의 경우 캐스트 연산자 (명시 적 또는 암시 적)를 제공해야합니다. 다음 EncodedString 클래스 예제는 사용자 지정 인코딩을 사용하는 문자열의 단순한 구현입니다 (.Net 문자열은 유니 코드이므로 모든 문자가 2 바이트의 메모리를 사용하기 때문에 거대한 문자열을 처리하고 메모리 소비 문제가 발생하는 경우 유용 할 수 있습니다. EncodedString은 문자 당 1 바이트를 사용할 수 있습니다.

EncodedString은 byte [] 및 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();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.