热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

对象类型使用“ref”和/或“out”-Using“ref”and/or“out”forObjecttype

Imstuckwith.Net1.1application(i.e.Icannotusethegenericsgoodiesfrom2.0fornow),and

I'm stuck with .Net 1.1 application (i.e. I can not use the generics goodies from 2.0 for now), and I was trying to optimize some parts of the code. As it deals a lot with runtime callable wrappers, which need to be released, I ended up to create a utility method which loops until all references are released. The signature of the method is:

我坚持使用.Net 1.1应用程序(即我现在不能使用2.0中的泛型好东西),我试图优化代码的某些部分。因为它需要释放运行时可调用包装器,所以我最终创建了一个实用程序方法,它循环直到所有引用都被释放。该方法的签名是:

void ReleaseObject(object comObject)

After releasing all comObjects, I call GC.Collect and GC.WaitForPendingFinalizers (don't ask - anybody dealing with Office interop knows).

释放所有comObject后,我调用GC.Collect和GC.WaitForPendingFinalizers(不要问 - 任何处理Office互操作的人都知道)。

And ... as usual, I hit a corner case - if I do not assign the corresponding managed reference to null before the GC.Collect call, it does not cleanup properly.

并且...像往常一样,我遇到了一个极端情况 - 如果我在GC.Collect调用之前没有将相应的托管引用分配给null,则它不能正确清理。

So, my code looks like:

所以,我的代码看起来像:

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

As, there are a bunch of xxx=null, I decided to put this in the util method, but as there is a difference between passing by reference, and passing a reference parameter, obviously I had to change the method to:

因为,有一堆xxx = null,我决定将它放在util方法中,但由于传递引用和传递引用参数之间存在差异,显然我不得不将方法更改为:

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

and edit the caller to:

并将调用者编辑为:

MyComClass myComObject = xxxx;
ReleaseObject(out myComObject);

This fails with a message: "Cannot convert from 'out MyComClass' to 'out object'"

这失败并显示一条消息:“无法从'输出MyComClass'转换为'输出对象'”

While I can think of why it can be a problem (i.e. the reverse cast from object to MyComClass is not implicit, and there is no guarantee what the method will do), I was wondering if there is a workaround, or I need to stay with my hundreds assignments of nulls.

虽然我可以想到为什么它可能是一个问题(即从对象到MyComClass的反向转换不是隐含的,并且不能保证该方法将做什么),我想知道是否有解决方法,或者我需要留下我的数百个空值分配。

Note: I have a bunch of different COM objects types, thats why I need a "object" parameter, and not a type safe one.

注意:我有一堆不同的COM对象类型,这就是为什么我需要一个“对象”参数,而不是一个类型安全的参数。

4 个解决方案

#1


2  

Why is it better to call a method than to just set the variable to null? They're both single line calls, and the latter is a lot simpler.

为什么调用方法比仅将变量设置为null更好?它们都是单线呼叫,后者更简单。

It does sound very odd that you need to set them to null in the first place though. Are these static variables, or instance variables whose values need to be released earlier than their containing object? If the variable is just a local variable which will go out of scope anyway, setting it to null shouldn't make any difference (in release).

虽然你需要将它们设置为null,但听起来很奇怪。这些静态变量或实例变量的值是否需要比其包含对象更早发布?如果变量只是一个局部变量,无论如何都会超出范围,将其设置为null不应该有任何区别(在发布中)。

Do the RCWs not implement IDisposable? If so, calling Dispose (preferably via a using statement) would be the best bet.

RCW不实现IDisposable吗?如果是这样,调用Dispose(最好通过using语句)将是最好的选择。

(After discussions in comments.)

(经过评论讨论后。)

These are local variables, which aren't referenced later in the method. That means the garbage collector will realise that they don't need to be treated as "root" references - so setting them to null shouldn't make any difference.

这些是局部变量,稍后在方法中不会引用。这意味着垃圾收集器将意识到它们不需要被视为“根”引用 - 因此将它们设置为null应该没有任何区别。

To answer the original question directly, however: no, you can't pass a variable by reference unless the method parameter is of exactly the same type, so you're out of luck here. (With generics it would be possible, but you've said you're limited to .NET 1.1.)

但是,要直接回答原始问题:不,你不能通过引用传递变量,除非方法参数的类型完全相同,所以你在这里运气不好。 (使用泛型它是可能的,但你已经说过你只限于.NET 1.1。)

#2


3  

Sunny, ref and out are a marshalling hints + contract to the compiler. Ref and out are a carryover to COM days - the marshalling hints for objects when sent over the wire / between processes.

Sunny,ref和out是编译器的编组提示+合同。 Ref和out是COM日的遗留物 - 通过线路/进程之间发送对象的编组提示。

The out contract

出合同

void foo( out MyClass x)
  1. foo() will set x to something before it returns.
  2. foo()会在返回之前将x设置为某个东西。

  3. x has no value when foo() is entered, and you get a compiler error if you attempt to use x before setting it. (use of unassigned out parameter x)
  4. 输入foo()时x没有值,如果在设置之前尝试使用x,则会出现编译器错误。 (使用未分配的参数x)

The ref contract

裁决合同

void foo( ref MyClass x)
  1. ref allows changing the callers reference.
  2. ref允许更改调用者引用。

  3. x has to be assignable
    • you cannot cast something to an intermediate variable foo( ref (object) something)
    • 你不能把东西投射到中间变量foo(ref(object)something)

    • x can not be a property
    • x不能是属性

  4. x必须是可赋值的你不能把东西转换成中间变量foo(ref(object)something)x不能是属性

The reality of the last two points are likely to stop you doing what you're trying to do, because in effect they make no sense when you understand what references really are. If you want to know that, ask Jon Skeet (he wrote a book).

最后两点的现实可能会阻止你做你想做的事情,因为实际上当你明白什么是真正的引用时它们没有任何意义。如果你想知道,请问Jon Skeet(他写了一本书)。

When marshalling ref, it says that in addition to the return value, bring back ref values as well. When marshalling out, it says don't bother sending the out value when the method is called, but remember to bring back the out value in addition to the return value.

编组ref时,它表示除了返回值之外,还要返回ref值。当编组时,它表示在调用方法时不打扰发送out值,但是记住除了返回值之外还要返回out值。


DISCLAIMER DISCLAIMER DISCLAIMER

免责声明免责声明

As others point out, something fishy is going on. It appears the brute-force code you are maintaining has some subtle bugs and suffers from coding by coincidence. The best solution is probably to add another layer of indirection. i.e. A wrapper to the wrapper class that ensures deterministic cleanup where you can write the messy code once and only once instead of peppering it throughout your codebase.

正如其他人指出的那样,一些可疑的东西正在发生。你维护的暴力代码似乎有一些微妙的错误,并且巧合编码。最好的解决方案可能是添加另一层间接。即包装器类的包装器,它确保确定性清理,您可以只编写一次杂乱的代码,而不是在整个代码库中编写它。


That said ..

那说..

Alternative 1

Ref won't do the trick unless you provide overloads for every type of (com) object you will call it with.

除非您为每个类型的(com)对象提供重载,否则Ref将不会执行此操作。

// 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(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.

Alternative 2

If you don't want to do that, return null from the Remove() method and cast back to the type of object.

如果您不想这样做,请从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 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

* I added generic versions for comparison.

*我添加了通用版本进行比较。

The above code has the effect that when looking at code you become suspicious when you see a call to Remove(x) without the assignment (making wrong code look wrong). You could even Grep through the codebase looking for calls to Remove where assignment doesn't take place.

上面的代码会产生这样的效果:在查看代码时,如果看到调用Remove(x)而没有赋值(使错误的代码看起来错误),则会变得可疑。您甚至可以通过代码库Grep查找在不进行分配的情况下调用Remove。


DISCLAIMER - all the above is predicated on your needing to set the reference to null manually, which (normally) isn't necessary.

免责声明 - 以上所有内容都取决于您是否需要手动将引用设置为null,这通常是不必要的。

#3


0  

In my opinion you won't be able to set those objects to null in another method (BTW you would need to use ref parameter instead of out to make it working, anyway you would hit the same problem with "Cannot convert..." error.) I'd recommend to create and array of objects and than iterate through that array, calling the ReleaseObject method and setting those objects to null. Something like:

在我看来,你将无法在另一种方法中将这些对象设置为null(顺便说一句,你需要使用ref参数而不是out来使其工作,无论如何你会遇到同样的问题“无法转换......”错误。)我建议创建对象数组,然后迭代遍历该数组,调用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();
...

#4


0  

You should be calling Marshal.ReleaseComObject, which AFAIK was available in 1.1.

您应该调用Marshal.ReleaseComObject,其中AFAIK在1.1中可用。

You probably mean "ref":

你可能的意思是“参考”:

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

[edit re comments] however, this will only work for untyped objects, so not much use without generics! Oh for C# 2.0...

[编辑注释]但是,这只适用于无类型的对象,所以没有泛型就没用多少!哦,对于C#2.0 ......

Re the "ref"; if the variables are truly variables (meaning: method variables), then they will go out of scope shortly and get collected. The "ref" would only be useful to release fields. But to be honest, it would be simpler just to set them to null...

重新“参考”;如果变量是真正的变量(意思是:方法变量),那么它们很快就会超出范围并被收集。 “ref”仅对释放字段有用。但说实话,将它们设置为null会更简单...

A typical COM pattern is:

典型的COM模式是:

SomeType obj = new SomeType();
try {
  obj.SomeMethod(); // etc
} finally {
  Marshal.ReleaseComObject(obj);
}

推荐阅读
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • 本文介绍了Python语言程序设计中文件和数据格式化的操作,包括使用np.savetext保存文本文件,对文本文件和二进制文件进行统一的操作步骤,以及使用Numpy模块进行数据可视化编程的指南。同时还提供了一些关于Python的测试题。 ... [详细]
  • 本文介绍了Foundation框架中一些常用的结构体和类,包括表示范围作用的NSRange结构体的创建方式,处理几何图形的数据类型NSPoint和NSSize,以及由点和大小复合而成的矩形数据类型NSRect。同时还介绍了创建这些数据类型的方法,以及字符串类NSString的使用方法。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
author-avatar
出典mosha
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有