문제

.NET 1.1 응용 프로그램 (예 : 현재 2.0의 제네릭 케이크를 사용할 수 없음)을 사용했으며 코드의 일부를 최적화하려고 노력했습니다. 출시 해야하는 런타임 호출 가능한 포장지를 많이 다루므로 모든 참조가 해제 될 때까지 루프가있는 유틸리티 방법을 만들었습니다. 방법의 서명은 다음과 같습니다.

void ReleaseObject(object comObject)

모든 comobjects를 출시 한 후 GC.Collect 및 GC.WaitForPendingFinalizers에 전화합니다 (사무실 인터 로프를 다루는 사람은 누구나 알고 있습니다).

그리고 ... 평소와 같이 코너 케이스를 쳤다 - GC.Collect 호출 전에 해당 관리 참조를 NULL에 할당하지 않으면 제대로 정리되지 않습니다.

그래서 내 코드는 다음과 같습니다.

ReleaseObject(myComObject);
myComObject = null;
GC.Collect()
...

XXX = NULL의 무리가 있으므로 UTIL 메소드에 이것을 넣기로 결정했지만 참조로 통과하는 것과 참조 매개 변수를 전달하는 것 사이에 차이가 있기 때문에 분명히 방법을 변경해야했습니다.

void ReleaseObject(out object comObject)
{
   //do release
   comObject = null;
}

발신자를 다음과 같이 편집하십시오.

MyComClass myComObject = xxxx;
ReleaseObject(out myComObject);

이것은 "MyComclass out '에서'Out Object '로 변환 할 수 없습니다."

왜 그것이 문제가 될 수 있는지 생각할 수 있지만 (즉, 객체에서 mycomclass로의 리버스 캐스트는 암시 적이 아니며, 방법이 무엇을할지 보장 할 수는 없습니다), 해결 방법이 있는지 궁금합니다. 수백 명의 널 과제로.

참고 : 다른 COM 객체 유형이 많기 때문에 "객체"매개 변수가 필요한 이유는 없으며 유형의 안전한 안전이 필요합니다.

도움이 되었습니까?

해결책

변수를 null로 설정하는 것보다 메소드를 호출하는 것이 더 나은 이유는 무엇입니까? 둘 다 한 줄의 호출이고 후자는 훨씬 간단합니다.

그래도 처음에 널로 설정해야한다는 것은 매우 이상하게 들립니다. 이러한 정적 변수 또는 값이 포함 된 객체보다 일찍 값을 출시 해야하는 인스턴스 변수입니까? 변수가 어쨌든 범위를 벗어나는 로컬 변수 인 경우 NULL로 설정하면 차이가 없어야합니다 (릴리스).

RCW가 idisposable을 구현하지 않습니까? 그렇다면 Discope (바람직하게는 사용 명세서를 통해) 호출하는 것이 가장 좋은 방법입니다.

(의견에 대한 토론 후.)

이들은이 방법의 뒷부분에서 참조되지 않은 로컬 변수입니다. 이는 쓰레기 수집가가 "루트"참조로 취급 될 필요가 없다는 것을 깨달을 것이므로 NULL로 설정하는 데 아무런 차이가 없어야합니다.

그러나 원본 질문에 직접 답변하려면 : 아니오, 메소드 매개 변수가 정확히 같은 유형이 아닌 한 변수를 참조별로 전달할 수 없으므로 여기서 운이 좋지 않습니다. (제네릭을 사용하면 가능하지만 .NET 1.1로 제한되어 있다고 말했습니다.)

다른 팁

Sunny, Ref and Out은 컴파일러와의 마샬링 힌트 + 계약입니다. Ref and Out은 Com Days로의 이월입니다. - 프로세스간에 전선을 통해 전송 될 때 개체에 대한 마샬링 힌트입니다.

그만큼 out 계약

void foo( out MyClass x)
  1. foo ()가 설정됩니다 x 돌아 오기 전에 무언가에.
  2. x foo ()를 입력 할 때 값이없고 사용하려고하면 컴파일러 오류가 발생합니다. x 설정하기 전에. (할당되지 않은 매개 변수 x의 사용)

그만큼 ref 계약

void foo( ref MyClass x)
  1. Ref는 발신자 참조를 변경할 수 있습니다.
  2. X는 할당 할 수 있어야합니다
    • 중간 변수 Foo (Ref (Object) Something)에 무언가를 캐스팅 할 수 없습니다.
    • X는 속성이 될 수 없습니다

마지막 두 지점의 현실은 당신이하려는 일을하는 것을 막을 가능성이 높습니다. 실제로 참고 문헌이 실제로 무엇인지 이해할 때 의미가 없기 때문입니다. 당신이 그것을 알고 싶다면, Jon Skeet에게 물어보십시오 (그는 책을 썼습니다).

참고 문헌을 마샬링 할 때 리턴 값 외에도 Ref 값도 다시 가져옵니다. 마샬링 할 때, 메소드가 호출 될 때 아웃 값을 보내지 말고 반환 값 외에도 아웃 값을 되 찾는 것을 잊지 마십시오.


면책 조항 면책 조항 면책 조항

다른 사람들이 지적한 것처럼 비린내가 진행되고 있습니다. 당신이 유지하고있는 무차별적인 코드에는 미묘한 버그가 있으며 우연의 코딩으로 어려움을 겪고 있습니다. 최상의 솔루션은 아마도 다른 간접 계층을 추가하는 것입니다. 즉, 코드베이스 전체에 후추 대신 지저분한 코드를 한 번만 작성할 수있는 결정 론적 정리를 보장하는 래퍼 클래스의 래퍼로.


그게 ..

대안 1

Ref는 당신이 호출 할 모든 유형의 (com) 객체에 과부하를 제공하지 않으면 트릭을 수행하지 않습니다.

// need a remove method for each type. 
void Remove( ref Com1 x ) { ...; x = null; }
void Remove( ref Con2 x ) { ...; x = null; }
void Remove( ref Com3 x ) { ...; x = null; }

// a generics version using ref.
void RemoveComRef<ComT>(ref ComT t) where ComT : class
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
    t = null; 
}

Com1 c1 = new Com1();
Com2 c2 = new Com2();
Remove( ref c1 );
RemoveComRef(ref c2); // the generics version again.

대안 2

그렇게하지 않으려면 remove () 메소드에서 null을 반환하고 객체 유형으로 다시 캐스트하십시오.

class Remover
{
    // .net 1.1 must cast if assigning
    public static object Remove(object x)
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(x);
        return null;
    }

    // uses generics.
    public static ComT RemoveCom<ComT>(ComT t) where ComT : class
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
        return null;
    }   
}

Com1 c1 = new Com1();
Com2 c2 = new Com2();
c1 = (Com1)Remover.Remove(c1); // no reliance on generics
c2 = Remover.RemoveCom(c2); // relies on generics

* 비교를 위해 일반 버전을 추가했습니다.

위의 코드는 코드를 볼 때 할당없이 (잘못된 코드를 잘못 보이게하는) 제거 호출을 볼 때 의심스러워지는 효과가 있습니다. 과제가 발생하지 않는 곳을 제거하기위한 통화를 찾는 코드베이스를 통해 심지어 GREP 일 수도 있습니다.


면책 조항 - 위의 모든 내용은 NULL에 대한 참조를 수동으로 설정 해야하는 경우 (일반적으로) 필요하지 않습니다.

제 생각에는 다른 방법으로 해당 객체를 NULL로 설정할 수 없습니다 (BTW를 사용해야합니다. 심판 대신 매개 변수 밖으로 어쨌든 "변환 할 수 없음 ..."오류로 동일한 문제를 겪게 될 것입니다.) 객체를 만들고 배열하는 것이 좋습니다. 해당 배열을 통해 반복하는 것보다 releaseObject 메소드를 호출하고 해당 객체를 NULL로 설정합니다. . 같은 것 :

List garbagedObjects = new List();
garbagedObjects.Add(myComObject1);
garbagedObjects.Add(myComObject2);
...
foreach(object garbagedObject in garbagedObjects)
{
  ReleaseObject(garbagedObject);
  garbagedObject = null;
}
garbagedObjects = null;
GC.Collect();
...

당신은 전화해야합니다 Marshal.ReleaseComObject, Afaik은 1.1에서 사용할 수있었습니다.

당신은 아마도 "ref"를 의미 할 것입니다 :

static void ReleaseObject(ref object comObject)
{
   if(comObject != null)
   {
     //do release
     comObject = null;
   }
}

편집 re 댓글] 그러나 이것은 유형적 인 객체에만 작동하므로 제네릭 없이는 많이 사용하지 않습니다! 오, C# 2.0의 경우 ...

"Ref"; 변수가 진정으로 변수 (의미 : 메소드 변수) 인 경우 곧 범위를 벗어나 수집됩니다. "Ref"는 필드를 해제하는 데만 유용합니다. 그러나 솔직히 말해서, 그것들을 null로 설정하는 것만 더 간단 할 것입니다 ...

일반적인 COM 패턴은 다음과 같습니다.

SomeType obj = new SomeType();
try {
  obj.SomeMethod(); // etc
} finally {
  Marshal.ReleaseComObject(obj);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top