문제

내가 기억하는 것을 읽고 무언가가는 방법에 대한 그것은 나쁜 구조체에 대해 인터페이스를 구현하에 CLR 를 통해 C#지만,나는 찾을 수 없는 것 그것에 대해 아무것도.그것은 나쁜가요?가가 의도하지 않은 결과 이렇게?

public interface Foo { Bar GetBar(); }
public struct Fubar : Foo { public Bar GetBar() { return new Bar(); } }
도움이 되었습니까?

해결책

거기에 여러 가지 이 질문은...

그것은 가능한 구조체에 대한 인터페이스를 구현하기 위해,그러나 우려가 있는 약을 가진 주물,가변성 및 성능을 갖추고 있습니다.이 게시물에 대한 더 많은 정보: http://blogs.msdn.com/abhinaba/archive/2005/10/05/477238.aspx

일반적으로,구조체에 사용해야 하는 개체가 가치-유형에 의미입니다.을 구현하여 인터페이스에서 구조체를 실행할 수 있습으로 복싱 문제로 구조체이 주의 앞뒤로 구조체와 인터페이스입니다.결과적으로의 복싱,를 변경하는 작업의 내부 상태는 구조체가 제대로 동작하지 않을 수 있습니다.

다른 팁

이후 다른 하나는 명시적으로 제공하는 이 대답이 다음을 추가합니다:

구현 인터페이스에서 구조체는 부정적인 결과입니다.

변수 인터페이스 유형을 사용하는 구조체에서 발생 박스의 가치는 구조체에 사용되고 있습니다.는 경우 구조체는 변경할 수 없(좋은 것)그런 다음 이에 최악의 성능 문제가 발생하지 않는 한 당신은:

  • 를 사용하여 결과에 대한 개체를 잠그는 목적(대단히 나쁜 생각하는 어떤 방법)
  • 를 사용하여 참조 평등을 의미와 기대하는 작업에 대한 두 개의 박스 값이 동일한 구조체.

이들 모두는 것,가능성이 대신 가능성이 있는 것 다음 중 하나를 수행합니다:

제네릭

아마도 많은 합리적인 사유 구조체에 대해 인터페이스를 구현하는 것은 그래서 그들이 사용할 수 있는 내 일반 컨텍스트 제약.에 사용되는 경우 이 패션 변수는 다음과 같이

class Foo<T> : IEquatable<Foo<T>> where T : IEquatable<T>
{
    private readonly T a;

    public bool Equals(Foo<T> other)
    {
         return this.a.Equals(other.a);
    }
}
  1. 사용할 수 있도록 구조체의 형식으로 매개변수
    • 그래서 다른 제약 조건과 같은 new()class 사용됩니다.
  2. 허용 회피의 권투에서 구조체에서 사용되는 방법입니다.

습니다.지 않는 인터페이스 참고 따라서 그것을 일으키지 않는 상자의 무엇을 배치합니다.할 때 더 c#컴파일러를 컴파일 일반적인 수업과 요구를 삽입하는 호출의 인스턴스는 방법에 정의된 형식의 인스턴스 매개 변수는 티를 사용할 수 있습니다 제약 opcode:

는 경우 이러한 종류의 값 입력 및 이러한 종류를 구현하는 방법은 다음 ptr 전달하더라도 수정되지 않는'이'포인터를 호출 방법은 명령 구현을 위한 방법으로 이러한 종류.

이것은 복싱과 때문에 값이 유형이 인터페이스를 구현하는 를 구현하는 방법에 따라서 복싱이 발생합니다.위 예제에서 Equals() 호출은 아무 상자에 이다.a1.

낮은 마찰 Api

가장 구조체가 있어야 원시인 같은 의미는 비트는 동일한 값이 동일한 것으로 간주됩2.런타임 공급할 것입니다 이러한 행동에 암시 Equals() 그러나 이것 속도가 느려질 수 있습니다.또한 이러한 암시적 평등은 로 노출의 구현 IEquatable<T> 따라서 막는 구조체를 사용되고 있으로 쉽게 열쇠를 위해 사지 않는 한 그들이 명시적으로 구현하고 있습니다그러므로 일반적인을 위해 많은 공용 구조체 유형을 선언하는 그들이 구현 IEquatable<T> (가 T 은 그들 각자)이 더 쉽고 더 좋은 공연 뿐만 아니라 일관적으로의 행동이 기존의 많은 가치 유형에 CLR BCL.

모든 프리미티브 BCL 구현에서 최소값:

  • IComparable
  • IConvertible
  • IComparable<T>
  • IEquatable<T> (따라서 IEquatable)

또한 많은 구현 IFormattable, 더 많은 시스템의 정의된 값이 유형이 같은 날짜/시간,기간 및 Guid 를 구현하는 많은 또는 이러한 모든뿐만 아니라.을 구현하는 경우 마찬가지로'널리 유용한'형식과 같은 복잡한 번호 구조체 또는 일부를 수정 폭을 텍스트로 값은 다음을 구현하는 많은 이들의 공통 인터페이스(올바르게)만들 것입니다 당신의 구조체에게 더 유용하고 사용할 수 있습니다.

제외

분명히는 경우 인터페이스를 강하게 의미 가변성 (등 ICollection 다)다음 구현하는 것은 나쁜 생각이 의미로 문신을 하나 만든 구조체의 변경(지도하는 종류의 오류를 설명하는 이는 수정에서 발생한 박스형 값보다는 원래)또는 당신은 사용자가 혼동을 무시하여 미치는 영향과 같은 방법 Add() 나 던지 예외가 있습니다.

많은 인터페이스를 의미하지는 않 가변성(예: IFormattable 다)및 역할은 관용적 방법을 노출하는 특정 기능이 일관성 있는 패션이다.자주 사용자의 구조체에 대해 걱정하지 않습니다 어떤 복싱을 위한 오버헤드 이러한 행동을 했다.

요약

할 때,눈에 띌 정도로에서 불변의 가치 유형의 구현에 유용한 인터페이스는 것이 좋


Notes:

1:참고하는 컴파일러를 사용할 수 있는 이 때를 호출하여 가상 방법에는 변수는 야의 특정 구조체 유형 하에서는 이를 호출하는 데 필요한 가상의 방법입니다.예를 들어:

List<int> l = new List<int>();
foreach(var x in l)
    ;//no-op

열거자를 반환에 의해 목록은 구조체의 최적화를 방지하는 할당을 열거할 때 목록(몇 가지 흥미로운 결과).그러나의 의미를 foreach 지정하는 경우 열거자를 구현하는 IDisposable 다음 Dispose() 될 것이라는 일단의 반복이 완료됩니다.분명히 이를 통해 발생 박스 호출을 제거하는 것이 어떤 혜택을 열거자는 구조체(사실 그것은 더 나쁠).더 나쁠 경우 폐기화 상태를 수정 열거의 어떤 방법으로 다음이 일어날 것에 박스 인스턴스와 많은 미묘한 버그 수도에서 소개 복잡한 경우.따라서 IL 에서 방출되는 상황이 이런 종류의 것:

IL_0001:  newobj      System.Collections.Generic.List..ctor
IL_0006:  stloc.0     
IL_0007:  nop         
IL_0008:  ldloc.0     
IL_0009:  callvirt    System.Collections.Generic.List.GetEnumerator
IL_000E:  stloc.2     
IL_000F:  br.s        IL_0019
IL_0011:  ldloca.s    02 
IL_0013:  call        System.Collections.Generic.List.get_Current
IL_0018:  stloc.1     
IL_0019:  ldloca.s    02 
IL_001B:  call        System.Collections.Generic.List.MoveNext
IL_0020:  stloc.3     
IL_0021:  ldloc.3     
IL_0022:  brtrue.s    IL_0011
IL_0024:  leave.s     IL_0035
IL_0026:  ldloca.s    02 
IL_0028:  constrained. System.Collections.Generic.List.Enumerator
IL_002E:  callvirt    System.IDisposable.Dispose
IL_0033:  nop         
IL_0034:  endfinally  

따라서의 구현 IDisposable 일으키지 않는 성능 문제 및(유감)변경 가능한 측면 열거자를 보존해야 하는 처분 방법을 실제로는 아무것도 할 수 있습니다!

2:더블트 이 규칙에 예외가 할머니는 값이 동일한 것으로 간주됩니다.

어떤 경우에 그것은 좋은 수 있습니다 구조체에 대하여 구현하여 인터페이스(면 그것은 결코 유용한,그것은 의심의 창조자.네트워가 제공됩니다).는 경우 구조체를 구현하는 읽기 전용 인터페이스 IEquatable<T>, 을 저장하는 구조체에 저장 위치(변수,매개변수,배열 요소,etc.) 의 유형 IEquatable<T> 이 필요는 박스(각각의 구조 형식을 실제로 정의는 두 가지 종류의 것:저장소 위치 유형으로 동작하는 값을 입력하고 힙-체 형식으로 동작하는 클래스 형식첫 번째는 암시적으로 변환하여 두 번째--"boxing"--두 번째로 변환할 수 있습니다 첫째를 통해 명시적인 캐스팅--"unboxing").그것은 이용 가능 구조체의 인터페이스 구현 없이 복싱을 사용하지만,무엇이라고 제한된 제네릭입니다.

는 경우,예를 들어,하나 있었 방법 CompareTwoThings<T>(T thing1, T thing2) where T:IComparable<T>, 같은 방법을 부를 수 있는 thing1.Compare(thing2) 하지 않고 상자 thing1thing2.는 경우 thing1 일어나야,예를 들어, Int32, 실행간다는 것을 알고 때를 위한 코드가 생성 CompareTwoThings<Int32>(Int32 thing1, Int32 thing2).는 것이기 때문에 알고 정확한 유형의 것을 호스팅하는 방법과하는 것의로 전달하는 매개변수,그것은 필요가 없거니다.

의 가장 큰 문제는 구조체를 구현하는 인터페이스는 구조체에 저장되는 위치의 인터페이스 유형 Object, 나 ValueType (반대로 위의 그것의 자신의 유형)으로 동작하는 클래스 개체입니다.에 대한 읽기 전용 인터페이스를 이것은 일반적으로 문제이지만,돌연변이와 같은 인터페이스 IEnumerator<T> 그것을 얻을 수 있습니다 어떤 이상한 의미입니다.

예를 들어,다음 코드:

List<String> myList = [list containing a bunch of strings]
var enumerator1 = myList.GetEnumerator();  // Struct of type List<String>.IEnumerator
enumerator1.MoveNext(); // 1
var enumerator2 = enumerator1;
enumerator2.MoveNext(); // 2
IEnumerator<string> enumerator3 = enumerator2;
enumerator3.MoveNext(); // 3
IEnumerator<string> enumerator4 = enumerator3;
enumerator4.MoveNext(); // 4

표시된 문#1prime enumerator1 을 읽는 첫 번째 요소입니다.의 상태는 열 복사됩 enumerator2.표시된 문#2 이 사전에 해당 복사본을 읽는 두 번째 요소이지만,에 영향을 미치지 않을 것입 enumerator1.의 상태는 두 번째 열거자는 그때로 복사 enumerator3, 게 될 고급여 표시된 문#3.후기 때문에, enumerator3enumerator4 모두 참조하 유형 REFERENCE 하기 enumerator3 후 복사할 enumerator4, 도록 표시된 문 것이 효과적으로 사전 모두 enumerator3enumerator4.

어떤 사람들은 척 하려고 그 가치 유형과 유형을 참조은 두 종류의 Object, 하지만 그건 사실이 아니에요.실제 값은 형식이 전환 Object, 지만,의 인스턴스가 아닙니다.의 인스턴스 List<String>.Enumerator 에 저장되는 위치의 유형은 가치 유형으로 작동 값 유형에 복사하는 위치의 유형 IEnumerator<String> 변환을 참조하 유형 로 동작 reference 유형.후자는 종류의 Object, 지만,전지 않습니다.

BTW,몇 가지 더 노트:(1)일반적으로,변경 가능한 클래스 형식이 있어야 그들의 Equals 테스트 방법을 참조 평등에 없지만 괜찮은 방법으로 박스 구조체는 그렇(2)그 이름에도 불구하고, ValueType 클래스 형식 헤어드라이어도 마련되어 유형모든 형태에서 파생 System.Enum 은 가치 유형으로,모든 유형에서 파생 ValueType 의 예외 System.Enum, 지만,모두 ValueTypeSystem.Enum 는 클래스 형식입니다.

구조체로 구현되는 값 형식과 클래스를 참조 형식입니다.이 있는 경우는 변수의 유형 Foo,그리고 당신은 스토어의 인스턴스 Linkedin 에 그것은,그것이"그것을 상자까지"참조 형식으로,따라서 물리치고 사용하는 장점에서 구조체는 첫 번째 장소입니다.

유일한 이유는 내가 보는 사용하는 구조체 클래스 대신은 것이기 때문에 값을 입력하고 참조 형,하지만 구조체 수 없는 상속받은 클래스에서.이 있는 경우 구조체 상속 인터페이스,그리고 당신은 주위에 전달 인터페이스,당신을 잃는 값 형식의 자연 구조체.수도뿐만 아니라 그냥 클래스가 필요할 경우 인터페이스가 있습니다.

(잘 주요 아무것도 추가 있지만 편집할 수직 그래서 여기에 간다..)
완벽하게 안전하다.아무 것도 불법적으로 구현하는 인터페이스에서 구조체.그러나 당신이 질문을 해야 이유를 원하는 그것을 할 수 있습니다.

그러나 를 취득하는 인터페이스를 참조하여 구조체이 상자 니다.그래서 성과 페널티과니다.

만이 유효한 시나리오에는 나의 생각할 수 있습이 지금 그림에서 나 여기 게시물.하려는 경우 수정하는 구조체의 상태로 저장된 컬렉션에서,당신은 그것을 할 수있 통해 추가 인터페이스에서 노출되는 구조체.

나는 생각한 문제는 그것이 원인이기 때문이 복싱 구조체는 가치 종류가 그래서 약간의 성능이 저하됩니다.

이 링크를 제안이 될 수 있는 다른 문제는 그것으로...

http://blogs.msdn.com/abhinaba/archive/2005/10/05/477238.aspx

기에 결과를 구현하는 구조체는 인터페이스입니다.예를 들어에 내장된 시스템을 구현하는 구조체의 인터페이스 IComparableIFormattable.

거기는 아주 작은 이유를 위한 값을 입력 인터페이스를 구현하기 위해.할 수 없기 때문에 하위 클래스 값을 입력할 수 있습니다 항상 그것을 참조로 구체적인 유형입니다.

지 않으면 물론,여러 개 있는 구조체를 모두 구현하는 동일한 인터페이스,수에 소폭 하락한 유용한 다만,그 시점에서 나는 권하고 싶을 사용하여 클래스고 바로 그것을하고있다.

물론,인터페이스를 구현하여,당신은 복싱 구조체,그래서 지금 그것에 앉아 있는 힙과할 수 없습니다 그것을 전달하는 값으로 더 이상이 정말 강화 내 생각하는 당신은 단지 클래스를 사용하는 이 상황입니다.

구조체가 그냥 좋아하는 클래스에서 라이브 스택입니다.나는 아무 이유 없이 왜 그들은"안전하지 않은".

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top