在方法中传递对派生对象的引用时出错
Posted
技术标签:
【中文标题】在方法中传递对派生对象的引用时出错【英文标题】:error when passing a reference to a derived object in a method 【发布时间】:2010-12-12 12:40:37 【问题描述】:在 c# 中,我试图实现一种方法,我可以使用该方法将数据绑定到我传递给它的任何控件(当然,前提是该控件是从 databoundcontrol 对象派生的)
给定方法
public void CTLBindData(ref DataBoundControl ctl) ...
尝试将派生控件传递给函数时出现错误 比如下面的代码
DropDownList lister = new DropDownList();
CTLBindData(ref lister);
产生转换错误
好吧,我可以接受,但以下让我感到困惑(可能是因为我习惯于 c++ 而不是 c#)
CTLBindData(ref (DataBoundControl)lister);
在这种情况下,我得到了错误 "一个 ref 或 out 参数必须是一个可赋值的变量"
为了澄清,Dropdownlist 继承自列表控件,而列表控件继承自 DataBoundControl
这对我来说毫无意义,我应该能够传入任何从数据绑定控件派生的对象。似乎是显式类型转换导致了问题。
关于我做错了什么的任何线索?
直流
【问题讨论】:
@Andrew 的答案是正确的,但是,你确定它必须通过 ref 传递吗?从逻辑上讲,您可能会返回不同类型的不同对象。如果你不打算在 CTLBindData 中为它分配新对象,那么在有和没有 ref 的情况下传递它是没有区别的。 你是说c#默认将对象作为引用而不是值传递吗?对我来说,你可以取回一个不同的对象是不合逻辑的,除非引用比实际引用更接近指针。 使用ref
可以让不同的对象返回。如果您阅读了我的答案中的链接,它的解释比我们任何人在评论中的解释都要好。
【参考方案1】:
使用具有适当类型参数约束的泛型函数:
public void CTLBindData<TControl>(ref TControl ctl)
where TControl : DataBoundControl
...
在调用中直接推断出类型,ocnstraint 确保控件是合适的类型。
【讨论】:
【参考方案2】:在调用方法之前进行转换:
DataBoundControl countrol = (DataBoundControl)lister;
CTLBindData(ref control);
C# 要求任何ref
参数为精确 类型(无多态性),并且该类型的引用必须是可分配的。这就是为什么您必须在单独的步骤中通过显式转换创建引用,以便该方法具有可以为其分配值的正确类型的引用。
有关此主题的更多信息,请参阅 Eric Lippert 的 Why do ref and out parameters not allow type variation?:
如果您有一个带有“X”的方法 那么你必须传递一个表达式 输入 X 或可转换为 X 的东西。 说,派生类型的表达式 从 X. 但是如果你有一个方法 需要一个“ref X”,你必须通过一个 引用 X 类型的变量,句点。 这是为什么?为什么不允许类型 变化,就像我们对非引用调用所做的那样?
【讨论】:
这不是复制控件并丢失其 Listbox 类还是 DataBoundControl countrol = (DataBoundControl)lister;创建对控件的引用? 您只是在创建引用的副本,而不是控件本身的副本。新的引用指向相同的对象,并且没有发生任何转换。 我想我现在明白了。在 c# 中,赋值 (=) 运算符创建对对象的引用,这与 c++ 中创建对象的副本不同,如果要在 c++ 中引用,则必须指定 & 运算符 @DeveloperChris - 正确,在 C# 中,您不能直接使用托管代码中的指针。【参考方案3】:Andrew Hare 回答得很好。
您的对象必须在内部需要一些东西才能使用 REF 或 OUT。例如:可以为空。
DropDownList lister = new DropDownList();
lister = null;
CTLBindData(ref lister);
【讨论】:
【参考方案4】:Andrew Hare 是正确的,但在这种情况下,您甚至可能不想使用 ref
。 C# 中的对象已经通过引用传递*。 (与值类型相反,除非您使用 ref
关键字,否则值类型不会通过引用传递。)我能想到的情况很少,您实际上需要以这种方式传递引用类型。如果没有ref
,您的原始代码应该可以正常工作。
**不是真的,但如果你来自非 C# 背景,这样更容易理解。引用实际上是按值传递的。 There is an excellent article 了解这一切是如何运作的。*
【讨论】:
虽然我同意这里可能不需要ref
,但重要的是要区分对象不是通过引用传递的。相反,对象引用是按值传递的。
确实如此。我在回答中添加了说明。以上是关于在方法中传递对派生对象的引用时出错的主要内容,如果未能解决你的问题,请参考以下文章