2016-07-26 6 views
-1

Похоже, что если для метода существует только один параметр массива типов, значение параметра, переданного моему методу LogException(), больше не является массивом.Первый элемент массива передается вместо целого массива

Если в методе есть несколько параметров или если один параметр не является массивом, он работает как ожидалось. Но когда я пытаюсь передать массив, кажется, что первое значение массива становится переданным параметром.

Все комментарии включены, чтобы объяснить и показать проблему. Сначала проблема возникает в «точке 4»; как только неправильное значение найдено, информация о параметрах, хранящаяся в моем исключении, неверна. В других пунктах выясняется последующая путаница, которая возникает. Я понятия не имею, как это решить.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Testapp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] tmp1 = new string[2]; 
      tmp1[0] = "val1"; 
      tmp1[1] = "val2"; 

      //please look at point 1 
      TestMethod1(tmp1); 
      //please look at point 2 
      TestMethod2(tmp1, "just a value"); 
     } 


     private static void TestMethod1(string[] ArrayType) 
     { 
      try 
      { 
       throw new System.Exception("blow"); 
      } 
      catch (System.Exception ex) 
      { 
       LogException(ex, ArrayType); 

       foreach (System.Collections.DictionaryEntry entry in ex.Data) 
       { 
        string tmp1 = entry.Key.ToString(); 
        string tmp2 = entry.Value.ToString(); 
        //point 1 (for param:ArrayType... well there is only 1 parameter) 
        //the value of tmp2 = val1 
        //and should be {val1,val2} 
        System.Diagnostics.Debugger.Break(); 
       } 
      } 
     } 
     private static void TestMethod2(string[] ArrayType, string StringType) 
     { 
      try 
      { 
       throw new System.Exception("blow"); 
      } 
      catch (System.Exception ex) 
      { 
       LogException(ex, ArrayType, StringType); 

       foreach (System.Collections.DictionaryEntry entry in ex.Data) 
       { 
        string tmp1 = entry.Key.ToString(); 
        string tmp2 = entry.Value.ToString(); 

        //point 2 (for param:ArrayType) 
        //the value of tmp2 = {val1,val2} (correct, this what i expected) 
        //please look at point 3 
        System.Diagnostics.Debugger.Break(); 
       } 
      } 
     } 

     [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
     public static void LogException(System.Exception Exception, params object[] args) 
     { 
      using (CallerInfo callerinfo = new CallerInfo(1)) 
      { 
       callerinfo.AddParameterInfo(Exception, args); 
      } 
     } 

     private class CallerInfo : IDisposable 
     { 
      private System.Reflection.ParameterInfo[] parameterinfos = null; 
      private string identifiername = string.Empty; 
      private string assemblyname = string.Empty; 

      public void AddParameterInfo(System.Exception Exception, params object[] sourceargs) 
      { 
       if (parameterinfos == null) return; 

       string locationname = identifiername + " - param:"; 
       foreach (System.Reflection.ParameterInfo ParameterInfo in parameterinfos) 
       { 
        string KeyName = locationname + ParameterInfo.Name; 
        object parameter = null; 
        try 
        { 
         System.Diagnostics.Debugger.Break(); 
         //point 4 
         //the next line goes wrong when there is ONLY 1 parameter on a method of type array 
         parameter = sourceargs[ParameterInfo.Position]; 

        } 
        catch 
        { 
         parameter = null; 
        } 
        if (parameter == null) 
        { 

         if (!Exception.Data.Contains(KeyName)) 
         { 
          Exception.Data.Add(KeyName, "*NULL*"); 
         } 
        } 
        else 
        { 
         if (ParameterInfo.ParameterType.IsArray) 
         { 
          //point 3 
          //this is where i got confused 
          //the check if (ParameterInfo.ParameterType.IsArray) is returning true.. correct the first parameter in both methods are of type array 
          //however for TestMethod1 (that is having ONLY 1 parameter) the value of parameter (see point 4) is NOT an array anymore????? 
          //for TestMethod2 (that is having 2 parameters, but the SAME first parameter as passed in TestMethod1) the value of parameter (see point 4) is an array what is correct 
          System.Diagnostics.Debugger.Break(); 
          if (parameter.GetType().IsArray) 
          { 
           string arrayvaluelist = "{"; 
           try 
           { 
            System.Collections.ArrayList arraylist = new System.Collections.ArrayList((System.Collections.ICollection)parameter); 
            foreach (object arrayitem in arraylist) 
            { 
             if (arrayitem == null) { arrayvaluelist = arrayvaluelist + "*NULL*,"; continue; } 
             arrayvaluelist = arrayvaluelist + arrayitem.ToString() + ","; 
            } 
            arrayvaluelist = arrayvaluelist.Substring(0, arrayvaluelist.Length - 1); 
            arrayvaluelist = arrayvaluelist + "}"; 
           } 
           catch 
           { 
            arrayvaluelist = "Error in constructing the arrayvalue list for parameter: " + ParameterInfo.Name; 
           } 
           if (!Exception.Data.Contains(KeyName)) 
           { 
            Exception.Data.Add(KeyName, arrayvaluelist); 
           } 
          } 
          else 
          { 
           //point 5 -- i shouldn't be here !!!! 
           System.Diagnostics.Debugger.Break(); 
           if (!Exception.Data.Contains(KeyName)) 
           { 
            Exception.Data.Add(KeyName, parameter.ToString() + " warning wrong value is returned."); 
           } 
          } 
         } 
         else 
         { 
          if (!Exception.Data.Contains(KeyName)) 
          { 
           Exception.Data.Add(KeyName, parameter.ToString()); 
          } 
         } 
        } 
       } 
      } 

      [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
      public CallerInfo(int Level) 
      { 
       try 
       { 
        System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); 
        System.Reflection.MethodBase methodbase = stackTrace.GetFrame(Level + 1).GetMethod(); 
        parameterinfos = methodbase.GetParameters(); 
        assemblyname = methodbase.ReflectedType.Assembly.ManifestModule.Name; 
        identifiername = methodbase.ReflectedType.FullName + "." + methodbase.Name; 
       } 
       catch 
       { 
        //broken 
       } 
      } 
      void IDisposable.Dispose() 
      { 
       parameterinfos = null; 
      } 
     } 
    } 
} 

ответ

1

Большое спасибо за товар Minimal, Complete, and Verifiable code example. Хотя вопрос, который изначально был сформулирован, не был особенно ясен, наличие хорошего MCVE гарантировало, что точная проблема может быть легко понята. (К сожалению, три разных человека не потрудились взглянуть на самую важную часть вопроса & hellip; кажется, худшие вопросы встают на голосование, хотя в то время как непонятный вопрос, но который включает полный код — самых важная часть любого вопроса — получает вниз проголосовали :().


во всяком случае, вопрос здесь ваше использование params в связи с тем, что сам параметр является массивом. важно понимать, что params на самом деле означает: параметр, объявленный таким образом, - это - фактически массив и следует всем нормальным правилам для регулярных параметров массива. Единственное, что дает вам params, это то, что вы может необязательно заполнить массив, предоставив несколько значений аргументов, и компилятор примет эти значения и объединит их в массив.

У вас возникли проблемы: если вы предоставите массив как значение аргумента, компилятор рассматривает это как фактический аргумент массива, который был объявлен для этого метода, и не выполняет никакой дополнительной работы.

Вопрос может быть более очевидным, если вы пропустили object[] вместо string[]. В этом случае вы можете легко увидеть, что весь массив object[] точно соответствует типу параметра для метода LogException() и поэтому передается напрямую, а не хранится в другом object[]. Как это бывает, массивы в C# являются «ковариантными». В этом случае главное, что означает, что если метод ожидает массив object[], вы можете передать ему массив любого типа, потому что элементы переданного массива наследуют тип object.

Итак, когда вы передаете значение ArrayType, компилятор С # распознает это как совместимый с object[] типа параметра в LogException() метода, а просто передает сам массив в качестве этого параметра, а не хранить его в качестве единственного элемента в object[]. Затем, когда вы переходите к извлечению значений параметров, кажется, что ваш метод LogException() был вызван методом с двумя разными параметрами, то есть двумя значениями string"val1" и "val2" соответственно.

Итак, как это исправить?Очень просто: нужно просто скрыть природу массив значения из C# компилятор с целью вызова:

LogException(ex, (object)ArrayType); 

Т.е. в вашем методе TestMethod1(), приведите ArrayType значение object при звонке LogException(). Это заставит компилятор обрабатывать объект массива как простое значение object, не позволяя ему сопоставлять тип значения с типом параметра params object[] args и сохранять значение в новом массиве object[] для вызова, как вы ожидали.

 Смежные вопросы

  • Нет связанных вопросов^_^