C# 为什么可以';我不能转换一个ref参数吗?

C# 为什么可以';我不能转换一个ref参数吗?,c#,C#,我有一个带有ref控件类型参数的方法,我想通过传递ref按钮类型参数来调用它 编译器不接受这个,我必须将ref控件类型更改为ref按钮类型 为什么?来自C#规范: 当形式参数是引用时 参数,对应的参数 在方法中,调用必须包括 关键字ref后跟一个 本标准的变量参考(§12.3.3) 与形式参数的类型相同 通常,ref需要精确的类型匹配,不允许显式或隐式转换 展示一些代码,以便我们讨论细节和备选方案 因为这会导致很多问题 public void DoDarkMagic(ref Control co

我有一个带有ref控件类型参数的方法,我想通过传递ref按钮类型参数来调用它

编译器不接受这个,我必须将ref控件类型更改为ref按钮类型

为什么?

来自C#规范:

当形式参数是引用时 参数,对应的参数 在方法中,调用必须包括 关键字ref后跟一个 本标准的变量参考(§12.3.3) 与形式参数的类型相同


通常,ref需要精确的类型匹配,不允许显式或隐式转换


展示一些代码,以便我们讨论细节和备选方案

因为这会导致很多问题

public void DoDarkMagic(ref Control control)
{
    control = new TextBox();
}

public void Main()
{
    Button button = new Button();

    DoDarkMagic(ref button);

    // Now your button magically became a text box ...
}
根据C#规范:

当形式参数是引用参数时,方法调用中的相应参数必须包含关键字ref,后跟与形式参数类型相同的变量引用(§5.3.3)


否则,可能会将不适当类型的值(对复选框实例的按钮字段引用)分配给您传递的变量。

您可以通过泛型绕过某些类型限制

void Test<T>(ref T control)
   where T: Control
{
}
您可以将任何类型的引用传递到从控件派生的引用中

现实生活场景:

 protected static void BindCollection<T>(
        T list
        , ref T localVar
        , ref ListChangedEventHandler eh // the event handler
        , ListChangedEventHandler d) //the method to bind the event handler if null
        where T : class, IBindingList
    {
        if (eh == null)
            eh = new ListChangedEventHandler(d);

        if (list != null && list != localVar)
        {
            if (localVar != null)
                localVar.ListChanged -= eh;

            localVar = list;

            list.ListChanged += eh;
        }
        else if (localVar != null && list == null)
        {
            localVar.ListChanged -= eh;
            localVar = list;
        }
    }

public override BindingList<ofWhatever> Children
    {
        get{//..}
        set
        {
           //woot! a one line complex setter 
           BindCollection(value, ref this._Children, ref this.ehchildrenChanged, this.childrenChanged);
        }
    }
受保护的静态void BindCollection(
T列表
,ref T localVar
,ref listchangedventhandler eh//事件处理程序
,ListChangedEventHandler d)//如果为null,则绑定事件处理程序的方法
其中T:class,IBindingList
{
如果(eh==null)
eh=新的列表更改控制器(d);
if(list!=null&&list!=localVar)
{
if(localVar!=null)
localVar.ListChanged-=eh;
localVar=list;
list.ListChanged+=eh;
}
else if(localVar!=null&&list==null)
{
localVar.ListChanged-=eh;
localVar=list;
}
}
公共覆盖绑定列表子项
{
获取{/..}
设置
{
//呜呜!一行复杂的二传手
BindCollection(值,ref this.\u Children,ref this.ehchildrenChanged,this.childrenChanged);
}
}

我很好奇,考虑到你正在传递一个对象,
ref
是否有必要。嗯,编程新手。可能需要考虑一个新的句柄。5年后你还会想要那个手柄吗?你好,谢谢你的解决方案,而我刚才问为什么这么好,我会选择你的答案作为最佳答案。是的,很抱歉。。。虽然我真的很喜欢一般的ref技巧,但我发现你的用法不是很好。通常应该避免列表类型属性的(公共)设置器。在什么情况下使用该代码?我通常同意,在大多数情况下,它实际上是私有的,我从延迟加载的getter调用该方法。我有很多对象的子集合都是延迟加载的,而这个模型(我截断它以便在SO上查看)确保了我在不复制和粘贴代码的情况下获得一致的绑定。我想再多解释一下会对他有所帮助。我怀疑他对某些东西不清楚,他的例子有代码味道。
 protected static void BindCollection<T>(
        T list
        , ref T localVar
        , ref ListChangedEventHandler eh // the event handler
        , ListChangedEventHandler d) //the method to bind the event handler if null
        where T : class, IBindingList
    {
        if (eh == null)
            eh = new ListChangedEventHandler(d);

        if (list != null && list != localVar)
        {
            if (localVar != null)
                localVar.ListChanged -= eh;

            localVar = list;

            list.ListChanged += eh;
        }
        else if (localVar != null && list == null)
        {
            localVar.ListChanged -= eh;
            localVar = list;
        }
    }

public override BindingList<ofWhatever> Children
    {
        get{//..}
        set
        {
           //woot! a one line complex setter 
           BindCollection(value, ref this._Children, ref this.ehchildrenChanged, this.childrenChanged);
        }
    }