RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 839834
Accepted
Алексей Федотов
Алексей Федотов
Asked:2020-06-09 18:10:22 +0000 UTC2020-06-09 18:10:22 +0000 UTC 2020-06-09 18:10:22 +0000 UTC

返回数组的泛型方法的语法

  • 772

有必要编写一个泛型方法,该方法接受一个数字数组(int、long 等),向每个元素添加一些相同类型的常量,然后返回一个新数组。我试图这样实现它:

static public T[] SomeMethod<T>(T[] myArray, T myConst)
    {
        T[myArray.Length] resultArray = default(T);

        for (int counter = 0; counter < myArray.Length; counter++)
        {
            resultArray[counter] = myArray[counter] + myConst;
        }
        return resultArray;
    }

首先,根据 Shield 4.0,这种泛型方法的语法如下:return_type method_name<list_of_type_parameters>(list_of_parameters) {...}。这里马上就出现了一个问题——是否有必要在方法名称后的尖括号中指定参数列表?之前实现其他方法,我没有这样做,一切正常。这是否意味着没有必要?其次,在此方法中声明新 resultArray 的局部变量时,出现错误,解释如下:“'T' is an type that is not valid in this context.” 但为什么?毕竟,代替所有 <> 将有一个类型作为参数传递,包括我在哪里创建一个新的结果数组。为什么会出现这个错误?我也尝试至少部分解决这个问题,

static public T[] SomeMethod<T>(T[] myArray, T myConst)
    {
        for (int counter = 0; counter < myArray.Length; counter++)
        {
            myArray[counter] = myArray[counter] + myConst;
        }
        return myArray;
    }

但是,在这种情况下,在行 myArray[counter] = myArray[counter] + myConst; 发生错误“运算符'+'不能应用于'T'和'T'类型的操作数”。我也不明白这个错误。我在做什么错,以及如何解决问题?

c#
  • 4 4 个回答
  • 10 Views

4 个回答

  • Voted
  1. test123
    2020-06-09T19:08:01Z2020-06-09T19:08:01Z

    如果您仍然需要将逻辑移出循环,我可以提供几个选项:

    1. 通过 lambda 公开逻辑:

      private delegate T Callback<T>(T value);
      
      private static T[] Do<T>(ref T[] array, Callback<T> callback){
          T[] newArray = new T[array.Length];
          for(int i=array.Length-1; i>=0; i--){
              newArray[i] = callback(array[i]);
          }
          return newArray;
      }
      
      private static void print<T>(T[] array) {
          foreach (T item in array) {
              Console.Write(item.ToString()+" ");
          }
          Console.Write("\n");
      }
      
      public static void Main(string[] args) {
      
          int[]   array1 = new int[]  {1,    2,    3};
          float[] array2 = new float[]{1.0f, 2.0f, 3.0f};
      
          print(array1);
          print(Do(ref array1,(int value)=>{
              return value+1;
          }));
      
          print(array2);
          print(Do(ref array2,(float value)=>{
              return value*2;
          }));
      
          Console.ReadKey();
      }
      

    这里编译器已经知道参数的类型,所以操作符不会有问题。使用一个元素的所有逻辑都在 lambda 函数中取出。

    1. 使用反射(纯理论):

      private static T[] Sum<T>(ref T[] array, T value){
          T[] newArray = new T[array.Length];
          MethodInfo plusMethod = typeof(T).GetMethod("op_Addition", BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance);
          for(int i=array.Length-1; i>=0; i--){
              newArray[i] = (T)plusMethod.Invoke(null, new object[] { array[i], value });
          }
          return newArray;
      }
      
      private static void print<T>(T[] array) {
          foreach (T item in array) {
              Console.Write(item.ToString()+" ");
          }
          Console.Write("\n");
      }
      
      public static void Main(string[] args) {
      
          MyClass[] array = new MyClass[] { new MyClass(1), new MyClass(2), new MyClass(3)};
      
          print(array);
          print(Sum(ref array, new MyClass(1)));
      
          Console.ReadKey();
      }
      

    这个选项的问题是原始类型没有 + 运算符,这个对原始数字的操作不再由尖锐本身执行。因此,纯粹从技术上讲,调用你的类将类似于 instance += anotherInstance;

    • 3
  2. Best Answer
    Alexander Petrov
    2020-06-09T19:15:54Z2020-06-09T19:15:54Z

    最简单的方法是使用dynamic. 但是,这很慢,并且可能在运行时崩溃。

    static public T[] SomeMethod<T>(T[] myArray, T myConst)
    {
        for (int counter = 0; counter < myArray.Length; counter++)
        {
            dynamic item = myArray[counter];
            item += myConst;
            myArray[counter] = item;
        }
        return myArray;
    }
    
    • 2
  3. tym32167
    2020-06-09T21:06:54Z2020-06-09T21:06:54Z

    对于初学者来说,为每个操作创建一个单独的方法是没有意义的。因此,最好将转换操作作为参数传递。

    让我们从一个简单的例子开始

    public T[] Transform<T>(T[] source, Func<T, T> transform)
    {
        var result = new T[source.Length];      
        for(var i=0; i<source.Length; i++)
            result[i] = transform(source[i]);           
        return result;
    }
    

    这个例子有两个明显的缺点:

    1. 它不是静态的,这意味着它会吃掉内存
    2. 它总是返回相同类型的集合

    让我们解决这个问题并将其实现为扩展方法:

    public static class Ext
    {
        public static K[] Transform<T, K>(this T[] source, Func<T, K> transform)
        {
            var result = new K[source.Length];      
            for(var i=0; i<source.Length; i++)
                result[i] = transform(source[i]);           
            return result;
        }
    }
    

    它已经看起来更好了。它可以这样使用:

    var result = new[] {1, 2, 3}.Transform(x=>x.ToString());
    

    但这种方法也有缺点。

    1. 它仅适用于数组
    2. 每次调用它都会分配新的内存

    例如,这个表达式

    var result = new[] {1, 2, 3}
        .Transform(x=>x.ToString())
        .Transform(int.Parse)
        .Transform(x=>x+10);
    

    它将分配内存 3 次,尽管我们实际上只需要一次。可以做什么?为了扩大消费者的圈子,您不仅可以在数组上运行该方法,还可以在枚举的所有内容上运行该方法。为了尽量减少内存分配,可以根本不分配内存,而是使用惰性枚举。它看起来像什么:

    public static class Ext
    {
        public static IEnumerable<K> Transform<T, K>(this IEnumerable<T> source, Func<T, K> transform)
        {
            foreach(var item in source)
                yield return transform(item);
        }
    }
    

    这样做的好处是现在的表达式

    var result = new[] {1, 2, 3}
        .Transform(x=>x.ToString())
        .Transform(int.Parse)
        .Transform(x=>x+10);
    

    在明确枚举结果之前,根本不会计算任何东西。大约根据这种机制,Linq Select功能可以工作,也可以在您的情况下使用。

    也就是说,其实表达式可以改写成这样

    var result2 = new[] { 1, 2, 3 }
        .Select(x => x.ToString())
        .Select(int.Parse)
        .Select(x => x + 10);
    

    它和我们刚刚写的一样,只是不使用我们的函数。

    • 2
  4. B. Vandyshev
    2020-06-09T23:10:19Z2020-06-09T23:10:19Z

    你确定你需要 SomeMethod 吗?因为您可以在需要的地方使用 Linq。

        var array = new[] { 1, 2, 3, 4 };
        var myConst = 1;
        var result = array.Select(x => x + myConst).ToArray();
    
    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5