Thoughts on the way of passing. NET parameters

  • 2021-09-04 23:56:52
  • OfStack

The following is a brief introduction to the usage of some common parameters of NET. If there are any deficiencies, please correct them. Welcome to leave a message below to discuss and share your opinions.

1. Overview of DotNet parameters:

In. NET, the parameter (formal parameter) variable is part 1 of the method or indexer declaration, and the argument is the expression used when calling the method or indexer.

In CLR, all method parameters are passed by value by default. When an object of reference type is passed, a reference to 1 object is passed to the method. Here, the ship reference itself is passed to the method by value. This also means that the method can modify the object, and the caller can see these modifications. For an instance of a value type, pass a copy of the instance of the method. Means that the method will get a copy of its dedicated 1 value type instance, and the instance in the caller will not be affected.

In CLR, parameters are allowed to be passed by reference rather than by value, and in C #, out and ref are used to pass value by reference. In C #, out and ref are used to pass a value by passing a reference. These two keywords tell the compiler to generate metadata to indicate that the parameter is passing a reference, and the compiler will generate code to pass the address of the parameter instead of passing the parameter itself. Using out and ref for value types is equivalent to passing reference types by value.

Commonly used parameters mainly include basic type parameters, generic parameters, and <in T>和<out T>,dynamic Wait. For example < in T > And < out T > In CLR, the variability of generic types was supported, C # acquired the syntax necessary to live generic ergodicity in 4.0, and now the compiler can know the possible conversion of interfaces and delegates. Variability is a type-safe way in which one object is used as another. Variability applies to the type parameters of generic interfaces and generic delegates. Covariance is used to return the value of an operation to the caller; Inversion means that the caller passes in the value to API; Invariance is relative to covariance and inverse variability, which means that nothing will happen. For this aspect of the knowledge is very rich, interested in their own understanding, here will not do a detailed introduction. Type dynamic, C # is a statically typed language, and in some cases the C # compiler looks for a specific name rather than an interface. dynamic can do anything at compile time and be processed by the framework at execution time. The introduction to dynamic types does not go into more depth.

In. NET, parameters are mainly used as optional parameters, named parameters, variable number of parameters and so on. The following part of this paper mainly introduces the use of these three parameters.

2. DotNet parameter usage:

The following mainly introduces the usage of three parameters: optional parameters; Named arguments; Pass a variable number of parameters.

1. Optional parameters:

(1). Basic usage:

If an operation requires more than one value, and some values tend to be the same every time it is called, you can usually use optional parameters. Before C #, variable parameters were implemented, often declaring a method containing all possible parameters, which was called by other methods and passed the appropriate default value.

Among the optional parameters, when designing parameters for 1 method, you can assign default values to some or all of the parameters. When calling these methods, the code can choose not to specify some arguments and accept the default values. You can also pass arguments to a method by specifying its name when it is called. Examples are as follows:


 static void OptionalParameters(int x, int y = 10, int z = 20)
  {
   Console.WriteLine("x={0} y={1} z={2}",x,y,z);
  }

 OptionalParameters(1, 2, 3);
   OptionalParameters(1, 2);
   OptionalParameters(1);

The above example clearly shows its usage. int y=10 and int z=20 are optional parameters. In the use of optional parameters, the C # compiler will automatically embed the default value of the parameter if one parameter is omitted during the call. When you pass arguments to a method, the compiler evaluates the arguments in left-to-right order. When you pass arguments with named arguments, the compiler still evaluates the arguments in left-to-right order.

(2). Basic principles:

Optional parameters include 1 specification, and the specific 1 requirements are as follows:

(a). All optional parameters must appear after prerequisite parameters, except for parameter arrays (declared using the params modifier), but they must appear at the end of the parameter list, preceded by optional parameters.

(b). Arrays of parameters cannot be declared optional. If the caller does not specify a value, an empty array is used instead.

(c). Optional parameters cannot use ref and out modifiers.

(d). The optional parameter can be of any type, but there is one restriction to the specified default value, which is that the default value must be a constant (numeric or string literal, null, const member, enumeration member, default (T) operator).

(e). The specified value is implicitly converted to a parameter type, but this conversion cannot be user-defined.

(f). Default values can be specified for methods, constructors, parameters with arguments, and parameters that are part of delegate 1.

(g). C # does not allow the omission of arguments between commas.

When using optional parameters, use null as the default value for reference types, and if the parameter type is a value type, only use the corresponding nullable value type as the default value.

(3). Code example:


 /// <summary>
  ///  Extract exception and its internal exception stack trace 
  /// </summary>
  /// <param name="exception"> Extracted exceptions </param>
  /// <param name="lastStackTrace"> The last extracted stack trace (for recursion),  String.Empty or null</param>
  /// <param name="exCount"> Number of stacks extracted (for recursion) </param>
  /// <returns>Syste.String</returns>
  public static string ExtractAllStackTrace(this Exception exception, string lastStackTrace = null, int exCount = 1)
  {
   while (true)
   {
    var ex = exception;
    const string entryFormat = "#{0}: {1}\r\n{2}";
    lastStackTrace = lastStackTrace ?? string.Empty;
    lastStackTrace += string.Format(entryFormat, exCount, ex.Message, ex.StackTrace);
    if (exception.Data.Count > 0)
    {
     lastStackTrace += "\r\n Data: ";
     lastStackTrace = exception.Data.Cast<DictionaryEntry>().Aggregate(lastStackTrace, (current, entry) => current + $"\r\n\t{entry.Key}: {exception.Data[entry.Key]}");
    }
    // Recursively add internal exceptions 
    if ((ex = ex.InnerException) == null) return lastStackTrace;
    exception = ex;
    lastStackTrace = $"{lastStackTrace}\r\n\r\n";
    exCount = ++exCount;
   }
  }

2. Named arguments:

The above explains some basic concepts and usage of optional parameters. Next, look at the related operation usage of named parameters under 1:

(1). Basic usage:

Named arguments mean that when you specify the value of an argument, you can also specify the corresponding parameter name. The compiler will determine whether the name of the parameter is correct and assign the specified value to the parameter. Named parameters precede each argument with their parameter name and a colon. The following code:


new StreamWriter(path:filename,aooend:true,encoding:realEncoding);

If you want to name a parameter that contains ref and out, you need to place the ref and out modifiers after the name and before the argument.


int number;
bool success=int.TryParse("10",result:out number);

(2). Basic principles:

In named arguments, all named arguments must be after positional arguments, and the position between them cannot be changed. A positional argument always points to the corresponding argument in the method declaration and cannot be specified by naming the corresponding positional argument after the parameter is skipped. The arguments are still evaluated in the order in which they are written, even though this order may differ from the order in which the parameters are declared.

In one case, the optional parameters are used in conjunction with the named reality. Optional parameters increase the number of applicable methods, while named entities reduce the number of methods used. To check if there is a specific applicable method, the compiler builds a list of passed-in arguments using the order of positional arguments, and then matches the named arguments with the remaining arguments. If a required parameter is not specified, or a named argument cannot match the remaining parameters, then this method is not applicable.

Named arguments can sometimes be used instead of casting to assist the compiler in overloading decisions. If the method is called from outside the module, it is potentially dangerous to change the default value of the parameter. You can pass arguments by name to arguments that do not have default values, but all required arguments must be passed for the compiler to compile code.

When writing C # code to interoperate with COM object model, the optional parameter and named parameter function of C # is best used. When calling an COM component, C # also allows to omit REF/OUT in order to pass an argument by reference. When using COM component, C # requires that OUT. REF keyword must be applied to the argument.

3. Pass a variable number of parameters:

In project development, sometimes we need to define a method to get a variable number of parameters. params can be used, and params can only be applied to the last 1 parameter in the method signature. The params keyword tells the compiler to apply an instance of System. ParamArrayAttribute to the parameter. Let's look at the code implemented under 1:


[AttributeUsage(AttributeTargets.Parameter, Inherited=true, AllowMultiple=false), ComVisible(true), __DynamicallyInvokable]
public sealed class ParamArrayAttribute : Attribute
{
 // Methods
 [__DynamicallyInvokable]
 public ParamArrayAttribute();
}
[__DynamicallyInvokable]
public ParamArrayAttribute()
{
}

It can be seen from the above code that this class inherits from Attribute class, which may be familiar to Attribute class, that is, the base class for defining custom attributes, which shows that ParamArrayAttribute class is used to define custom attributes, ParamArrayAttribute class has only one construction method under System namespace, and there is no specific implementation. AttributeUsage also defines how attributes are used.

When the C # compiler detects a method call, it checks all methods with the specified name and parameters that do not have ParamArrayAttribute applied. If a matching method is found, the compiler generates the code needed to call it. If the compiler does not find a matching method, it directly checks the method that applies ParamArrayAttribute. If a matching method is found, the compiler generates code to construct an array, populate its elements, and generate code to call the selected method.

Invoking a method with a variable number of parameters causes an additional performance loss, array objects must be allocated on pairs, array elements must be initialized, and array memory must eventually be garbage collected.

1 method code is provided for reference only:


 /// <summary>
  ///  Character type 2 Dimensional array is converted to DataTable 
  /// </summary>
  /// <param name="stringDyadicArray"></param>
  /// <param name="messageOut"></param>
  /// <param name="dataTableColumnsName"></param>
  /// <returns></returns>
  public DataTable DyadicArrayToDataTable(string[,] stringDyadicArray, out bool messageOut,
   params object[] dataTableColumnsName)
  {
   if (stringDyadicArray == null)
   {
    throw new ArgumentNullException("stringDyadicArray");
   }
   var returnDataTable = new DataTable();
   if (dataTableColumnsName.Length != stringDyadicArray.GetLength(1))
   {
    messageOut = false;
    return returnDataTable;
   }
   for (var dataTableColumnsCount = 0;dataTableColumnsCount < dataTableColumnsName.Length;dataTableColumnsCount++)
   {
    returnDataTable.Columns.Add(dataTableColumnsName[dataTableColumnsCount].ToString());
   }
   for (var dyadicArrayRow = 0; dyadicArrayRow < stringDyadicArray.GetLength(0); dyadicArrayRow++)
   {
    var addDataRow = returnDataTable.NewRow();
    for (var dyadicArrayColumns = 0; dyadicArrayColumns < stringDyadicArray.GetLength(1);dyadicArrayColumns++)
    {
     addDataRow[dataTableColumnsName[dyadicArrayColumns].ToString()] = stringDyadicArray[dyadicArrayRow, dyadicArrayColumns];
    }
    returnDataTable.Rows.Add(addDataRow);
   }
   messageOut = true;
   return returnDataTable;
  }

Above given a variable number of parameters and named parameters of the use of the sample, completed the 2-dimensional byte array into DataTable object, the array traversal, and the array written into datatable, the logic of the whole method is not in-depth introduction, code comparison is simple.

3. Some guiding principles related to parameters:

When declaring a method's parameter type, try to specify the weakest type, preferably the interface rather than the base class.

Among the basic principles of design patterns, Dimitri's rule is also the least knowledge principle. Dimitri's rule means that if two classes do not have to communicate directly with each other, then these two classes should not interact directly. If one of the classes needs to call one of the methods of the other class, the call can be forwarded through the third. In the design of class structure, every class should minimize the access rights of members. The weaker the coupling degree between classes, the more beneficial it is to reuse. A weakly coupled class is modified, which will not affect related classes.

In the use of parameters, we still need to think carefully and seriously about the use of parameter types, because the definition of parameter types affects the expansibility and stability of our program to a certain extent. If the constraints of parameter types are relatively large, it is of great significance to the expansion of subsequent methods. In the whole object-oriented language system, the 1-cut design pattern is extended from "polymorphism", and interfaces and delegates are used a lot in our object-oriented design, with the aim of expanding the constraint of parameters when using them.

In the return value type of a method, the returned type should be declared as the strongest type, so as not to be limited to a specific type.

4. Summary:

The above is an article that briefly introduces method parameters, and the content of the article mainly introduces optional parameters, named parameters and so on. If there are any deficiencies in the above content, I hope you can forgive me and point out the corresponding problems. Knowledge precedes model, followed by reflection. After learning 1 point, we need to summarize and reflect on the connotation, so that we can have time, energy and ability to think.


Related articles: