سؤال

أنا عالق مع تطبيق .NET 1.1 (أي لا يمكنني استخدام الأشياء الجيدة من 2.0 في الوقت الحالي) ، وكنت أحاول تحسين بعض أجزاء الكود. نظرًا لأنه يتعامل كثيرًا مع الأغطية القابلة للاستدعاء في وقت التشغيل ، والتي يجب إصدارها ، انتهى بي الأمر لإنشاء طريقة فائدة تحلق حتى يتم إصدار جميع المراجع. توقيع الطريقة هو:

void ReleaseObject(object comObject)

بعد إصدار جميع comobjects ، أدعو GC.Collect و GC.WaitForpendingFinalizers (لا تسأل - أي شخص يتعامل مع Office interop يعرف).

و ... كالمعتاد ، ضربت حالة الزاوية - إذا لم أقم بتعيين الإشارة المدارة المقابلة إلى NULL قبل مكالمة GC.Collect ، فهي لا تنظف بشكل صحيح.

لذا ، يشبه الكود الخاص بي:

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

نظرًا لأن هناك مجموعة من xxx = null ، فقد قررت وضع هذا في طريقة UTIL ، ولكن نظرًا لوجود فرق بين المرور بالرجوع إليه ، وتمرير معلمة مرجعية ، من الواضح أنه كان عليّ تغيير الطريقة إلى:

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

وتعديل المتصل إلى:

MyComClass myComObject = xxxx;
ReleaseObject(out myComObject);

فشل هذا برسالة: "لا يمكن التحويل من" Out MyComclass "إلى" Out Object ""

على الرغم من أنني أستطيع التفكير في سبب وجود مشكلة (أي أن الممثل العكسي من كائن إلى MyComclass ليس ضمنيًا ، وليس هناك ما يضمن ما ستفعله الطريقة) ، كنت أتساءل عما إذا كان هناك حلول ، أو أحتاج إلى البقاء مع مئات مهام الفارغ.

ملاحظة: لدي مجموعة من أنواع كائنات COM المختلفة ، ولهذا السبب أحتاج إلى معلمة "كائن" ، وليس نوعًا آمنًا.

هل كانت مفيدة؟

المحلول

لماذا من الأفضل استدعاء طريقة بدلاً من ضبط المتغير على Null؟ كلاهما مكالمات خط واحد ، والأخير أبسط بكثير.

يبدو من الغريب أن تحتاج إلى ضبطها على الفرق في المقام الأول. هل هذه المتغيرات الثابتة ، أو متغيرات المثيل التي تحتاج إلى إصدار قيمها في وقت مبكر من كائنها المحتوي؟ إذا كان المتغير مجرد متغير محلي سيخرج من النطاق على أي حال ، فإن ضبطه على NULL يجب ألا يحدث أي فرق (في الإصدار).

هل لا تنفذ RCWS؟ إذا كان الأمر كذلك ، فإن الاتصال بالتخلص (ويفضل عبر بيان باستخدام) سيكون أفضل رهان.

(بعد مناقشات في التعليقات.)

هذه هي المتغيرات المحلية ، والتي لم تتم الإشارة إليها لاحقًا في هذه الطريقة. هذا يعني أن جامع القمامة سوف يدرك أنه لا يحتاج إلى معاملته كمراجع "جذر" - لذلك يجب ألا يحدث وضعها على أي فرق.

للإجابة على السؤال الأصلي مباشرة ، ومع ذلك: لا ، لا يمكنك تمرير متغير بالرجوع إليه ما لم تكن معلمة الطريقة ذات النوع نفسه تمامًا ، لذا فأنت محظوظ هنا. (مع الأداء الأولي ، سيكون ذلك ممكنًا ، لكنك قلت إنك تقتصر على .NET 1.1.)

نصائح أخرى

مشمسة ، المرجع والخارج هي عقد تلميحات + عقد إلى المترجم. المرجع والخارج هي ترحيل إلى أيام كوم - تلميحات الحشوة للكائنات عند إرسالها عبر السلك / بين العمليات.

ال out عقد

void foo( out MyClass x)
  1. سيتم تعيين Foo () x لشيء ما قبل أن يعود.
  2. x لا يوجد أي قيمة عند إدخال FOO () ، وستحصل على خطأ في المترجم إذا حاولت الاستخدام x قبل تعيينه. (استخدام المعلمة غير المعينة x)

ال ref عقد

void foo( ref MyClass x)
  1. المرجع يسمح بتغيير مرجع المتصلين.
  2. x يجب أن يكون قابلاً للتخصيص
    • لا يمكنك إلقاء شيء على متغير متغير foo (المرجع (الكائن) شيء)
    • X لا يمكن أن يكون خاصية

من المحتمل أن تمنعك حقيقة النقطتين الأخيرين أن تمنعك من فعل ما تحاول القيام به ، لأنه في الواقع لا معنى لهما عندما تفهم ما هي المراجع حقًا. إذا كنت تريد أن تعرف ذلك ، اسأل Jon Skeet (كتب كتابًا).

عند تنظيم المرجع ، يقول أنه بالإضافة إلى قيمة الإرجاع ، أعد قيم المرجع أيضًا. عند التنقل ، تقول لا تهتم بإرسال القيمة الخارجية عندما يتم استدعاء الطريقة ، ولكن تذكر إعادة القيمة الخارجية بالإضافة إلى قيمة الإرجاع.


إخلاء المسؤولية إخلاء المسئولية

كما يشير آخرون ، هناك شيء مريب يحدث. يبدو أن رمز القوة الغاشمة التي تحتفظ بها تحتوي على بعض الأخطاء الدقيقة وتعاني من الترميز عن طريق الصدفة. أفضل حل هو إضافة طبقة أخرى من عدم التوجيه. أي غلاف إلى فئة Wrapper التي تضمن التنظيف الحتمي حيث يمكنك كتابة الرمز الفوضوي مرة واحدة وفقط بدلاً من تفريقه عبر قاعدة الشفرة الخاصة بك.


هكذا قال ..

البديل 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

إذا كنت لا ترغب في القيام بذلك ، فأعود من طريقة REMOM () وإعادة إرجاعها إلى نوع الكائن.

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

* أضفت إصدارات عامة للمقارنة.

الرمز أعلاه له تأثير أنه عند النظر إلى الكود ، فإنك تصبح مشبوهًا عندما ترى مكالمة لإزالة (x) دون التعيين (جعل رمزًا خاطئًا يبدو خاطئًا). يمكنك حتى GREP من خلال قاعدة الشفرة التي تبحث عن مكالمات لإزالة أين لا تحدث المهمة.


إخلاء المسئولية - كل ما سبق مبني على حاجتك إلى تعيين الإشارة إلى NULL يدويًا ، والتي (عادةً) ليست ضرورية.

في رأيي ، لن تتمكن من ضبط هذه الكائنات على 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.

ربما تقصد "المرجع":

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

تحرير التعليقات] ومع ذلك ، فإن هذا سيعمل فقط مع كائنات غير معدّة ، لذلك لا يستخدم الكثير من الأدوار! أوه من أجل C# 2.0 ...

إعادة "المرجع" ؛ إذا كانت المتغيرات متغيرات حقًا (معنى: متغيرات الطريقة) ، فستخرج من النطاق قريبًا ويتم جمعها. سيكون "المرجع" مفيدًا فقط لإطلاق الحقول. ولكن بصراحة ، سيكون الأمر أكثر بساطة فقط لتعيينهم على الفرق ...

نمط COM النموذجي هو:

SomeType obj = new SomeType();
try {
  obj.SomeMethod(); // etc
} finally {
  Marshal.ReleaseComObject(obj);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top