【问题标题】:Generic Method assigned to Delegate分配给委托的通用方法
【发布时间】:2013-12-25 07:46:07
【问题描述】:

我对委托和通用方法有点困惑。

是否可以将委托分配给具有泛型类型参数的方法?

IE:

//This doesn't allow me to pass a generic parameter with the delegate.
public delegate void GenericDelegate<T>() 

someDelegate = GenericMethod;
public void GenericMethod<T>() where T : ISomeClass
{

}

我正在尝试将此委托传递给具有该方法所期望的接口的泛型类型的函数,其函数如下:

void CheckDelegate(GenericDelegate<ISomeClass> mechanism);

这样我就可以像这样使用委托了:

someDelegate<ImplementsSomeClass>();

【问题讨论】:

  • someDelegate 看起来像什么? (你得到了什么错误?)
  • 公共委托 void GenericDelegate();
  • "变量 'someDelegate' 不能与类型参数一起使用。"
  • 为什么不使用带 ISomeState 类型参数的委托?

标签: c# generics types interface delegates


【解决方案1】:

您的问题毫无意义,因为您永远不能使用开放的泛型类型来声明存储位置(如局部变量或字段)。它必须始终关闭。

我了解您希望将 GenericDelegate&lt;T&gt; 传递给将此类值作为参数的方法。但即便如此,委托类型也会以 T 作为泛型类型参数关闭。

在您编写的示例代码中

someDelegate = GenericMethod;

但是someDelegate 应该有什么类型?它必须要么明显关闭(GenericDelegate&lt;string&gt;),要么使用外部范围的泛型类型参数关闭:

void SomeOuterMethod<T>() where T : ISomeClass {
    GenericDelegate<T> someDelegate = GenericMethod<T>;
}

希望我能理解您的问题。如果不是,请澄清。如果您详细说明您想要完成什么,我会尝试提出一个实用的解决方案。

像 Haskell 这样的其他语言确实支持传递开放泛型类型的值(换句话说,您可以拥有一个 IEnumerable&lt;&gt; 类型的变量)。这是实现 monad 所必需的。 CLR 没有该功能。


新想法:您可以使用可被覆盖的泛型方法创建非泛型基类型,而不是委托:

interface CheckHandler {
 public void Check<T>(T someArg);
}

希望能涵盖您的情况。您不能随意传递任何CheckHandler。然后可以使用任意类型参数调用其Check 方法。

【讨论】:

  • 我正在尝试修改对象的状态。类型 T 将指定对象需要转换到的状态。
  • 很好地解释了为什么不能将代理称为someDelegate&lt;ClassThatImplementsSomeClass&gt;();。我完全同意。
  • 所以这是不可能的,因为当我将它作为 正确传递时,我将类型转换为关闭?
  • 我想是的。如果您想保持通用性,则必须将泛型类型参数添加到所有方法(或其周围类型),以便您能够将实际的泛型类型参数传递到所涉及的所有代码中。我在答案中添加了一个新想法。这有帮助吗?
  • @usr: 听起来像我在想的[查看我的答案]
【解决方案2】:

可能有一个“事物”可以对多种参数类型进行操作,但Delegate 类不适合这种情况。相反,您需要定义一个接口。举个简单的例子:

public interface IMunger<TConstraint>
{
    void Munge<T>(ref T it) where T : TConstraint;
}
public class Cloner : IMunger<ICloneable>
{
    public void Munge<T>(ref T it) where T : ICloneable
    {
        if (typeof(T).IsValueType) // See text
            return;
        it = (T)(it.Clone());
    }
}

即使系统有一个带有 by-ref 参数的预定义委托类型(例如 ActByRef&lt;ICloneable&gt; 将具有签名 void Invoke(ref ICloneable p1)),这种委托也只能用于精确类型为 ICloneable 的变量。相比之下,非泛型类类型Cloner 的单个对象能够提供适用于任何实现ICloneable 的存储位置类型的方法。另请注意,如果将ref 传递给一个持有对装箱值类型实例的引用的变量,它将用对实例副本的引用替换它,但如果将ref 传递给一个值类型变量,它保持原样(除非值类型将其状态保存在一个可变类对象中,它持有一个引用 - 一个非常狡猾的模式 - 说StructType foo = (StructType)(bar.Clone());将等同于@987654331 @; 结构类型可能想要实现ICloneable 以便允许它参与深度克隆层次结构,但这并不意味着它的Clone 方法需要做任何事情。

【讨论】:

    【解决方案3】:

    更新示例以支持方法作为参数,这只是说明如何将泛型委托作为其他方法的参数调用。

    class Program
    {
        public delegate T Transformer<T>(T arg) where T : IComparable;
    
        public static void Transform<T>(T value, Transformer<T> method) where T: IComparable
        {
            Console.WriteLine(method(value));
        }
    
        static void Main(string[] args)
        {
            Transform(5, Square);
        }
    
        static int Square(int x)
        {
            return x * x;
        }
    }
    

    【讨论】:

      【解决方案4】:

      我尝试了以下方法:

      public class Test
      {
          public interface ISomeClass { }
      
          public class ImplementsSomeClass : ISomeClass { }
      
          public delegate void GenericDelegate<T>() where T : ISomeClass;
      
          public void GenericMethod<T>() 
          {
              // EDIT: returns typeof(ImplementsSomeClass)
              var t = typeof(T); 
          }
      
          public void CheckDelegate(GenericDelegate<ISomeClass> mechanism)
          {
              // EDIT: call without generic argument since it is already determined 
              mechanism(); 
          }
      
          public void test()
          {
              GenericDelegate<ISomeClass> someDelegate = GenericMethod<ImplementsSomeClass>;
              CheckDelegate(someDelegate);
          }
      }
      

      而且我没有编译错误。是运行时问题还是我误解了您的问题描述?

      【讨论】:

      • 我想用泛型参数调用委托。
      • someDelegate();
      • 是否可以在不每次创建委托的情况下做到这一点?我正在寻找对为什么不能使用泛型参数调用 Delegates 的更深层次的理解。委托调用 someDelegate();真的是我要找的。​​span>
      • @10001110101 你不能这样做,因为传递的委托有它的通用参数集,因为我们将它定义为someDelegate = GenericMethod&lt;ImplementsSomeClass&gt;; 之后你不能用不同的参数调用它。有关更多信息,请参阅 usr 的答案。
      猜你喜欢
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-05
      • 1970-01-01
      相关资源
      最近更新 更多