1. <tfoot id='gmVpC'></tfoot>

        <i id='gmVpC'><tr id='gmVpC'><dt id='gmVpC'><q id='gmVpC'><span id='gmVpC'><b id='gmVpC'><form id='gmVpC'><ins id='gmVpC'></ins><ul id='gmVpC'></ul><sub id='gmVpC'></sub></form><legend id='gmVpC'></legend><bdo id='gmVpC'><pre id='gmVpC'><center id='gmVpC'></center></pre></bdo></b><th id='gmVpC'></th></span></q></dt></tr></i><div id='gmVpC'><tfoot id='gmVpC'></tfoot><dl id='gmVpC'><fieldset id='gmVpC'></fieldset></dl></div>
          <bdo id='gmVpC'></bdo><ul id='gmVpC'></ul>

        <small id='gmVpC'></small><noframes id='gmVpC'>

        <legend id='gmVpC'><style id='gmVpC'><dir id='gmVpC'><q id='gmVpC'></q></dir></style></legend>

        动作委托、泛型、协变和逆变

        Action delegates, generics, covariance and contravariance(动作委托、泛型、协变和逆变)
          <tfoot id='aCOUB'></tfoot>
              <tbody id='aCOUB'></tbody>

            1. <small id='aCOUB'></small><noframes id='aCOUB'>

                <legend id='aCOUB'><style id='aCOUB'><dir id='aCOUB'><q id='aCOUB'></q></dir></style></legend>
              • <i id='aCOUB'><tr id='aCOUB'><dt id='aCOUB'><q id='aCOUB'><span id='aCOUB'><b id='aCOUB'><form id='aCOUB'><ins id='aCOUB'></ins><ul id='aCOUB'></ul><sub id='aCOUB'></sub></form><legend id='aCOUB'></legend><bdo id='aCOUB'><pre id='aCOUB'><center id='aCOUB'></center></pre></bdo></b><th id='aCOUB'></th></span></q></dt></tr></i><div id='aCOUB'><tfoot id='aCOUB'></tfoot><dl id='aCOUB'><fieldset id='aCOUB'></fieldset></dl></div>
                  <bdo id='aCOUB'></bdo><ul id='aCOUB'></ul>
                  本文介绍了动作委托、泛型、协变和逆变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我有两个业务合同类:

                  public BusinessContract
                  
                  public Person : BusinessContract
                  

                  在另一个类中,我有以下代码:

                  In another class I have the following code:

                  private Action<BusinessContract> _foo;
                  
                  public void Foo<T>( Action<T> bar ) where T : BusinessContract
                  {
                      _foo = bar;
                  }
                  

                  上面的代码甚至无法编译,这让我有点困惑.我将 T 限制为 BusinessContract,那么为什么编译器不知道 bar 可以分配给 _foo?

                  The above won't even compile, which baffles me a bit. I'm constraining T to be BusinessContract, so why doesn't the compiler know that bar can be assigned to _foo?

                  为了解决这个问题,我们尝试将其更改为以下内容:

                  In trying to get around this, we tried changing it to the following:

                  public void Foo<T>( Action<T> bar ) where T : BusinessContract
                  {
                      _foo = (Action<BusinessContract>)bar;
                  }
                  

                  现在编译器很高兴,所以我在我的应用程序的其他地方编写了以下代码:

                  Now the compiler is happy, so I write the following code elsewhere in my application:

                  Foo<Person>( p => p.Name = "Joe" );
                  

                  应用程序在运行时因 InvalidCastException 而崩溃.

                  And the app blows up with an InvalidCastException at run-time.

                  我不明白.我不应该能够将我更具体的类型转换为不太具体的类型并分配它吗?

                  I don't get it. Shouldn't I be able to cast my more specific type to a less specific type and assign it?

                  更新

                  乔恩回答了这个问题,因此得到了点头,但只是为了结束这个循环,这就是我们最终解决问题的方法.

                  Jon answered the question so got the nod for that, but just to close the loop on this, here's how we ended up solving the problem.

                  private Action<BusinessContract> _foo;
                  
                  public void Foo<T>( Action<T> bar ) where T : BusinessContract
                  {
                      _foo = contract => bar( (T)contract );
                  }
                  

                  我们为什么要这样做?我们有一个用于单元测试的假 DAL.使用其中一种方法,我们需要让测试开发人员能够指定在测试期间调用该方法时应该做什么(它是一种从数据库更新缓存对象的刷新方法).Foo 的目的是设置调用 refresh 时应该发生什么.IOW,在本课程的其他地方,我们有以下内容.

                  Why are we doing this? We have a Fake DAL we use for unit testing. With one of the methods we need to give the test developer the ability to specify what the method should do when it's called during the test (it's a refresh method that updates a cached object from the database). The purpose of Foo is to set what should happen when refresh is called. IOW, elsewhere in this class we have the following.

                  public void Refresh( BusinessContract contract )
                  {
                      if( _foo != null )
                      {
                          _foo( contract );
                      }
                  }
                  

                  然后,例如,测试开发人员可以决定在调用 Refresh 时将名称设置为不同的值.

                  The test developer could then, for example, decide they wanted to set the name to a different value when Refresh was called.

                  Foo<Person>( p => p.Name = "New Name" );
                  

                  推荐答案

                  你把协变和逆变弄错了.让我们考虑 Action<object>Action<string>.删除实际的泛型,您正在尝试执行以下操作:

                  You've got the covariance and contravariance the wrong way round. Let's consider Action<object> and Action<string>. Removing the actual generics, you're trying to do something like this:

                  private Action<object> _foo;
                  
                  public void Foo(Action<string> bar)
                  {
                      // This won't compile...
                      _foo = bar;
                  }
                  

                  现在假设我们接着写:

                  _foo(new Button());
                  

                  这很好,因为 Action<object> 可以被传递 any 对象...但是我们已经用一个 必须 的委托对其进行了初始化> 接受一个字符串参数.哎哟.

                  That's fine, because Action<object> can be passed any object... but we've initialized it with a delegate which must take a string argument. Ouch.

                  这不是类型安全的,因此无法编译.

                  This isn't type safe, so doesn't compile.

                  不过, 的另一种方式也可以:

                  The other way would work though:

                  private Action<string> _foo;
                  
                  public void Foo(Action<object> bar)
                  {
                      // This is fine...
                      _foo = bar;
                  }
                  

                  现在当我们调用 _foo 时,我们必须 传入一个字符串 - 但这很好,因为我们已经用一个可以接受任何 object 引用作为参数,所以我们可以给它一个字符串.

                  Now when we invoke _foo, we have to pass in a string - but that's fine, because we've initialized it with a delegate which can take any object reference as a parameter, so it's fine that we happen to be giving it a string.

                  所以基本上 Action<T>逆变 - 而 Func协变:

                  So basically Action<T> is contravariant - whereas Func<T> is covariant:

                  Func<string> bar = ...;
                  Func<object> foo = bar; // This is fine
                  object x = foo(); // This is guaranteed to be okay
                  

                  不清楚你想用这个动作做什么,所以很遗憾,我无法就如何解决这个问题提供任何建议......

                  It's not clear what you're trying to do with the action, so unfortunately I can't really give any advice on how to get around this...

                  这篇关于动作委托、泛型、协变和逆变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

                  相关文档推荐

                  Multicast delegate weird behavior in C#?(C# 中的多播委托奇怪行为?)
                  Parameter count mismatch with Invoke?(参数计数与调用不匹配?)
                  How to store delegates in a List(如何将代表存储在列表中)
                  How delegates work (in the background)?(代表如何工作(在后台)?)
                  C# Asynchronous call without EndInvoke?(没有 EndInvoke 的 C# 异步调用?)
                  Delegate.CreateDelegate() and generics: Error binding to target method(Delegate.CreateDelegate() 和泛型:错误绑定到目标方法)

                  <i id='7ltmX'><tr id='7ltmX'><dt id='7ltmX'><q id='7ltmX'><span id='7ltmX'><b id='7ltmX'><form id='7ltmX'><ins id='7ltmX'></ins><ul id='7ltmX'></ul><sub id='7ltmX'></sub></form><legend id='7ltmX'></legend><bdo id='7ltmX'><pre id='7ltmX'><center id='7ltmX'></center></pre></bdo></b><th id='7ltmX'></th></span></q></dt></tr></i><div id='7ltmX'><tfoot id='7ltmX'></tfoot><dl id='7ltmX'><fieldset id='7ltmX'></fieldset></dl></div>

                    • <bdo id='7ltmX'></bdo><ul id='7ltmX'></ul>

                          <small id='7ltmX'></small><noframes id='7ltmX'>

                            <tbody id='7ltmX'></tbody>

                          <legend id='7ltmX'><style id='7ltmX'><dir id='7ltmX'><q id='7ltmX'></q></dir></style></legend>
                        • <tfoot id='7ltmX'></tfoot>