Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Por defeito, C# passa argumentos para funções por valor. Esta abordagem passa uma cópia da variável ao método. Para tipos de valor (struct), o método obtém uma cópia do valor. Para tipos de referência (class), o método obtém uma cópia da referência. Podes usar modificadores de parâmetros para passar argumentos por referência.
Como uma struct é um tipo de valor, passar uma struct por valor a um método envia uma cópia do argumento para o método. O método funciona com esta cópia. O método não consegue aceder à estrutura original no método de chamada nem pode alterá-la. O método pode alterar apenas a cópia.
Uma instância de classe é um tipo de referência, não um tipo de valor. Quando passa um tipo de referência por valor para um método, o método recebe uma cópia da referência para a instância. Ambas as variáveis se referem ao mesmo objeto. O parâmetro é uma cópia da referência. O método chamado não pode reatribuir a instância no método de chamada. No entanto, o método chamado pode usar a cópia da referência para acessar os membros da instância. Se o método chamado alterar um membro da instância, o método de chamada também verá essas alterações, pois faz referência à mesma instância.
A referência da linguagem C# documenta a versão mais recentemente lançada da linguagem C#. Contém também documentação inicial para funcionalidades em versões preliminares públicas para a próxima versão da linguagem.
A documentação identifica qualquer funcionalidade introduzida pela primeira vez nas últimas três versões da língua ou em pré-visualizações públicas atuais.
Sugestão
Para saber quando uma funcionalidade foi introduzida pela primeira vez em C#, consulte o artigo sobre o histórico de versões da linguagem C#.
Passe por valor e passe por referência
Todos os exemplos nesta seção usam os dois tipos de record a seguir para ilustrar as diferenças entre class tipos e tipos struct:
public record struct Point(int X, int Y);
// This doesn't use a primary constructor because the properties implemented for `record` types are
// readonly in record class types. That would prevent the mutations necessary for this example.
public record class Point3D
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
A saída do exemplo a seguir ilustra a diferença entre passar um tipo struct por valor e passar um tipo de classe por valor. Ambos Mutate os métodos alteram os valores das propriedades do seu argumento. Quando o parâmetro é um struct tipo, essas alterações afetam uma cópia dos dados do argumento. Quando o parâmetro é um class tipo, essas alterações afetam a instância referida pelo argumento:
public class PassTypesByValue
{
public static void Mutate(Point pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void Mutate(Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
pt.Z = 42;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void TestPassTypesByValue()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Mutate(ptStruct);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Mutate(ptClass);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Mutate: Point { X = 1, Y = 2 }
// Exit Mutate: Point { X = 19, Y = 23 }
// After called Mutate: Point { X = 1, Y = 2 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Mutate: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Mutate: Point3D { X = 19, Y = 23, Z = 42 }
// After called Mutate: Point3D { X = 19, Y = 23, Z = 42 }
}
}
O modificador ref é uma maneira de passar argumentos por referência a métodos. O código seguinte replica o exemplo anterior, mas passa os parâmetros por referência. As modificações feitas no tipo struct são visíveis no método de chamada quando a struct é passada por referência. Não há alteração semântica quando um tipo de referência é passado por referência:
public class PassTypesByReference
{
public static void Mutate(ref Point pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void Mutate(ref Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
pt.Z = 42;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void TestPassTypesByReference()
{
Console.WriteLine("===== Value Types =====");
var pStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{pStruct}");
Mutate(ref pStruct);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pStruct}");
Console.WriteLine("===== Reference Types =====");
var pClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{pClass}");
Mutate(ref pClass);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Mutate: Point { X = 1, Y = 2 }
// Exit Mutate: Point { X = 19, Y = 23 }
// After called Mutate: Point { X = 19, Y = 23 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Mutate: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Mutate: Point3D { X = 19, Y = 23, Z = 42 }
// After called Mutate: Point3D { X = 19, Y = 23, Z = 42 }
}
}
Os exemplos anteriores modificaram propriedades de um parâmetro. Um método também pode reatribuir um parâmetro a um novo valor. A reatribuição se comporta de forma diferente para os tipos struct e class quando passada por valor ou por referência. O exemplo a seguir mostra como os tipos struct e os tipos de classe se comportam quando os parâmetros que são passados pelo valor são reatribuídos:
public class PassByValueReassignment
{
public static void Reassign(Point pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point { X = 13, Y = 29 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void Reassign(Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point3D { X = 13, Y = 29, Z = -42 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void TestPassByValueReassignment()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Reassign(ptStruct);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Reassign(ptClass);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Reassign: Point { X = 1, Y = 2 }
// Exit Reassign: Point { X = 13, Y = 29 }
// After called Reassign: Point { X = 1, Y = 2 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Reassign: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Reassign: Point3D { X = 13, Y = 29, Z = -42 }
// After called Reassign: Point3D { X = 1, Y = 2, Z = 3 }
}
}
O exemplo anterior mostra que, quando você reatribui um parâmetro a um novo valor, essa alteração não é visível a partir do método de chamada, independentemente de o tipo ser um tipo de valor ou um tipo de referência. O exemplo seguinte mostra o comportamento quando se reatribui um parâmetro que o método recebe por referência:
public class PassByReferenceReassignment
{
public static void Reassign(ref Point pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point { X = 13, Y = 29 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void Reassign(ref Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point3D { X = 13, Y = 29, Z = -42 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void TestPassByReferenceReassignment()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Reassign(ref ptStruct);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Reassign(ref ptClass);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Reassign: Point { X = 1, Y = 2 }
// Exit Reassign: Point { X = 13, Y = 29 }
// After called Reassign: Point { X = 13, Y = 29 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Reassign: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Reassign: Point3D { X = 13, Y = 29, Z = -42 }
// After called Reassign: Point3D { X = 13, Y = 29, Z = -42 }
}
}
O exemplo anterior mostra como a reatribuição do valor de um parâmetro que é passado por referência é visível no contexto de chamada.
Contexto seguro de referências e valores
Os métodos podem armazenar os valores dos parâmetros em campos. Quando passa parâmetros por valor, normalmente é seguro. O método copia valores, e os tipos de referência são acessíveis quando o método os armazena num campo. Passar parâmetros por referência com segurança requer que o compilador defina quando é seguro atribuir uma referência a uma nova variável. Para cada expressão, o compilador define um contexto seguro que limita o acesso a uma expressão ou variável. O compilador usa dois escopos: safe-context e ref-safe-context.
- O contexto seguro define o escopo onde qualquer expressão pode ser acessada com segurança.
- O ref-safe-context define o escopo onde uma referência a qualquer expressão pode ser acessada ou modificada com segurança.
Informalmente, você pode pensar nesses escopos como o mecanismo para garantir que seu código nunca acesse ou modifique uma referência que não é mais válida. Uma referência é válida desde que se refira a um objeto ou struct válido. O contexto seguro define quando uma variável pode ser atribuída ou reatribuída. O ref-safe-context define quando uma variável pode ser atribuída ref ouref reatribuída. A atribuição atribui uma variável a um novo valor; A atribuição ref atribui a variável para se referir a um local de armazenamento diferente.
Parâmetros de referência
Para passar argumentos por referência em vez de por valor, use um dos seguintes modificadores numa declaração de parâmetro:
-
ref: Inicialize o argumento antes de chamar o método. O método pode atribuir um novo valor ao parâmetro, mas não é obrigatório. -
out: O método que chama não precisa de inicializar o argumento antes de chamar o método. O método deve atribuir um valor ao parâmetro. -
ref readonly: Inicialize o argumento antes de chamar o método. O método não pode atribuir um novo valor ao parâmetro. -
in: Inicialize o argumento antes de chamar o método. O método não pode atribuir um novo valor ao parâmetro. O compilador pode criar uma variável temporária para manter uma cópia do argumento parainparâmetros.
Um parâmetro que é passado por referência é uma variável de referência. Não tem valor próprio. Em vez disso, refere-se a uma variável diferente chamada seu referente. Podes reatribuir variáveis de referência por referência , o que altera o seu referente.
Os membros de uma classe não podem ter assinaturas que diferem apenas por ref, ref readonly, in, ou out. Um erro de compilador ocorre se a única diferença entre dois membros de um tipo for que um membro tem um ref parâmetro e o outro tem um out, ref readonly, ou in parâmetro. No entanto, pode sobrecarregar métodos quando um método tem um ref, ref readonly, inou out parâmetro e o outro método tem um parâmetro que é passado por valor, como mostrado no exemplo seguinte. Em outras situações que exigem correspondência de assinatura, como ocultar ou substituir, in, , ref, ref readonlye out fazem parte da assinatura e não correspondem entre si.
Quando um parâmetro tem um dos modificadores anteriores, o argumento correspondente pode ter um modificador compatível:
- Um argumento para um
refparâmetro deve incluir orefmodificador. - Um argumento para um
outparâmetro deve incluir ooutmodificador. - Um argumento para um
inparâmetro pode, opcionalmente, incluir oinmodificador. Se orefmodificador for usado no argumento, o compilador emitirá um aviso. - Um argumento para um
ref readonlyparâmetro deve incluir osinmodificadores ourefmodificadores, mas não ambos. Se nenhum dos modificadores estiver incluído, o compilador emitirá um aviso.
Quando você usa esses modificadores, eles descrevem como o argumento é usado:
-
refsignifica que o método pode ler ou gravar o valor do argumento. -
outsignifica que o método define o valor do argumento. -
ref readonlysignifica que o método lê, mas não pode escrever o valor do argumento. O argumento deve ser passado por referência. -
insignifica que o método lê, mas não pode escrever o valor do argumento. O argumento é transmitido por referência ou através de uma variável temporária.
Não é possível usar os modificadores de parâmetro anteriores nos seguintes tipos de métodos:
- Métodos assíncronos, que você define usando o modificador assíncrono.
- Métodos iteradores, que incluem um retorno de rendimento ou
yield breakuma instrução.
Os membros da extensão também têm restrições quanto ao uso destas palavras-chave de argumentos:
- A
outpalavra-chave não pode ser usada no primeiro argumento de um método de extensão. - A
refpalavra-chave não pode ser usada no primeiro argumento de um método de extensão quando o argumento não é umstruct, ou um tipo genérico não restrito a ser um struct. - As
ref readonlypalavras-chave einnão podem ser usadas a menos que o primeiro argumento seja umstruct. - As
ref readonlypalavras-chave einnão podem ser usadas em nenhum tipo genérico, mesmo quando restritas a ser uma estrutura.
As propriedades não são variáveis. São métodos. Não podes usar propriedades como argumentos para ref parâmetros.
ref modificador de parâmetros
Para usar um ref parâmetro, tanto a definição do método quanto o método de chamada devem usar explicitamente a ref palavra-chave, conforme mostrado no exemplo a seguir. (Só que o método de chamada pode ser omitido ref ao fazer uma chamada COM.)
void Method(ref int refArgument)
{
refArgument = refArgument + 44;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
Tens de inicializar um argumento antes de o passar para um ref parâmetro.
out modificador de parâmetros
Para usar um out parâmetro, tanto a definição do método quanto o método de chamada devem usar explicitamente a out palavra-chave. Por exemplo:
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
void OutArgExample(out int number)
{
number = 44;
}
Não precisas de inicializar variáveis passadas como out argumentos antes da chamada ao método. No entanto, o método chamado deve atribuir um valor antes de regressar.
Os métodos Deconstruct declaram seus parâmetros com o out modificador para retornar vários valores. Outros métodos podem retornar tuplas de valor para vários valores de retorno.
Você pode declarar uma variável em uma instrução separada antes de passá-la como um out argumento. Você também pode declarar a out variável na lista de argumentos da chamada de método, em vez de em uma declaração de variável separada.
out As declarações de variáveis produzem um código mais compacto e legível e também impedem que você atribua inadvertidamente um valor à variável antes da chamada do método. O exemplo a seguir define a number variável na chamada para o método Int32.TryParse .
string numberAsString = "1640";
if (Int32.TryParse(numberAsString, out int number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
Você também pode declarar uma variável local digitada implicitamente.
ref readonly modificador
A declaração do método requer o ref readonly modificador. Um modificador no site de chamada é opcional. Podes usar o in modificador ou ref . O ref readonly modificador não é válido no site de chamada. O modificador que usar no site da chamada pode ajudar a descrever as características do argumento. Só podes usar ref se o argumento for uma variável e for escrivo. Só podes usar in quando o argumento é uma variável. A variável pode ser gravável ou apenas de leitura. Não podes adicionar nenhum dos modificadores se o argumento não for uma variável, mas sim uma expressão. Os exemplos a seguir mostram essas condições. O método a seguir usa o ref readonly modificador para indicar que uma estrutura grande deve ser passada por referência por motivos de desempenho:
public static void ForceByRef(ref readonly OptionStruct thing)
{
// elided
}
Pode chamar o método usando o ref modificador ou.in Se você omitir o modificador, o compilador emitirá um aviso. Quando o argumento é uma expressão, não uma variável, você não pode adicionar os in modificadores ou ref , então você deve suprimir o aviso:
ForceByRef(in options);
ForceByRef(ref options);
ForceByRef(options); // Warning! variable should be passed with `ref` or `in`
ForceByRef(new OptionStruct()); // Warning, but an expression, so no variable to reference
Se a variável for uma readonly variável, você deve usar o in modificador. O compilador emite um erro se você usar o ref modificador em vez disso.
O ref readonly modificador indica que o método espera que o argumento seja uma variável em vez de uma expressão que não é uma variável. Exemplos de expressões que não são variáveis são constantes, valores de retorno de método e propriedades. Se o argumento não for uma variável, o compilador emitirá um aviso.
in modificador de parâmetros
O in modificador é necessário na declaração do método, mas desnecessário no local de chamada.
var largeStruct = new LargeStruct { Value1 = 42, Value2 = 3.14, Value3 = "Hello" };
// Using 'in' avoids copying the large struct and prevents modification
ProcessLargeStruct(in largeStruct);
Console.WriteLine($"Original value unchanged: {largeStruct.Value1}");
// Without 'in', the struct would be copied (less efficient for large structs)
ProcessLargeStructByValue(largeStruct);
Console.WriteLine($"Original value still unchanged: {largeStruct.Value1}");
void ProcessLargeStruct(in LargeStruct data)
{
// Can read the values
Console.WriteLine($"Processing: {data.Value1}, {data.Value2}, {data.Value3}");
// Uncomment the following line to see error CS8331
// data.Value1 = 99; // Compilation error: cannot assign to 'in' parameter
}
void ProcessLargeStructByValue(LargeStruct data)
{
// This method receives a copy of the struct
Console.WriteLine($"Processing copy: {data.Value1}, {data.Value2}, {data.Value3}");
// Modifying the copy doesn't affect the original
data.Value1 = 99;
}
O in modificador permite ao compilador criar uma variável temporária para o argumento e passar uma referência apenas de leitura para esse argumento. O compilador sempre cria uma variável temporária quando o argumento deve ser convertido, quando há uma conversão implícita do tipo de argumento ou quando o argumento é um valor que não é uma variável. Por exemplo, quando o argumento é um valor literal ou o valor retornado de um acessador de propriedade. Quando sua API exigir que o argumento seja passado por referência, escolha o ref readonly modificador em vez do in modificador.
Pode obter otimização de desempenho definindo métodos com in parâmetros. Alguns struct argumentos de tipo podem ser grandes, e quando se chamam métodos em laços apertados ou caminhos críticos de código, o custo de copiar essas estruturas é substancial. Declara in parâmetros para especificar que podes passar argumentos por referência em segurança porque o método chamado não modifica o estado desse argumento. Passar esses argumentos por referência evita a cópia (potencialmente) cara. Você adiciona explicitamente o in modificador no site de chamada para garantir que o argumento seja passado por referência, não por valor. O uso in explícito tem os dois efeitos a seguir:
- A especificação
inno local de chamada força o compilador a selecionar um método definido com um parâmetro correspondentein. Caso contrário, quando dois métodos diferem apenas na presença dein, a sobrecarga por valor é uma melhor correspondência. - Ao especificar
in, você declara sua intenção de passar um argumento por referência. O argumento usado comindeve representar um local que pode ser diretamente referido. Aplicam-se as mesmas regrasoutgerais erefargumentos: não é possível usar constantes, propriedades ordinárias ou outras expressões que produzam valores. Caso contrário, omitirinno site de chamada informa ao compilador que não há problema em criar uma variável temporária para passar por referência somente leitura para o método. O compilador cria uma variável temporária para superar várias restrições cominargumentos:- Uma variável temporária permite constantes de tempo de compilação como
inparâmetros. - Uma variável temporária permite propriedades ou outras expressões para
inparâmetros. - Uma variável temporária permite argumentos onde há uma conversão implícita do tipo de argumento para o tipo de parâmetro.
- Uma variável temporária permite constantes de tempo de compilação como
Em todas as instâncias anteriores, o compilador cria uma variável temporária que armazena o valor da constante, propriedade ou outra expressão.
O código a seguir ilustra essas regras:
static void Method(in int argument)
{
// implementation removed
}
Method(5); // OK, temporary variable created.
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // OK, temporary int created with the value 0
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // passed by readonly reference
Method(in i); // passed by readonly reference, explicitly using `in`
Agora, suponha que outro método usando argumentos por valor estava disponível. Os resultados mudam conforme mostrado no código a seguir:
static void Method(int argument)
{
// implementation removed
}
static void Method(in int argument)
{
// implementation removed
}
Method(5); // Calls overload passed by value
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // Calls overload passed by value.
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // Calls overload passed by value
Method(in i); // passed by readonly reference, explicitly using `in`
A única chamada de método em que o argumento é passado por referência é a final.
Nota
O código anterior usa int como o tipo de argumento para simplicidade. Como int não é maior do que uma referência na maioria das máquinas modernas, não há benefício em passar um único int como referência apenas de leitura.
params modificador
O parâmetro com a params palavra-chave deve ser o último parâmetro na declaração do método. Só pode usar uma params palavra-chave numa declaração de método.
Deve declarar o params parâmetro como um tipo de coleção. Tipos de coleções reconhecidos incluem:
- Um tipo
T[]de array unidimensional, onde o tipo de elemento éT. - Um tipo de extensão:
System.Span<T>System.ReadOnlySpan<T>
Nestes tipos, o tipo de elemento éT.
- Um tipo com um método de criação acessível que tem um tipo de elemento correspondente. O método create utiliza o mesmo atributo que as expressões de coleção.
- Um struct ou tipo de classe que implementa System.Collections.Generic.IEnumerable<T> onde:
- O tipo tem um construtor que pode invocar sem argumentos, e o construtor é pelo menos tão acessível quanto o membro declarante.
- O tipo tem um método
Addde instância (não uma extensão) onde:- O método pode ser invocado com um único argumento de valor.
- Se o método for genérico, os argumentos de tipo podem ser inferidos a partir do argumento.
- O método é pelo menos tão acessível quanto o membro declarante. Neste caso, o tipo de elemento é o tipo de iteração do tipo.
- Um tipo de interface:
Antes de C# 13, deve usar um array unidimensional para o parâmetro.
Quando você chama um método com um params parâmetro, você pode passar:
- Uma lista separada por vírgulas de argumentos do tipo dos elementos da matriz.
- Uma coleção de argumentos do tipo especificado.
- Sem argumentos. Se você não enviar argumentos, o
paramstamanho da lista será zero.
O exemplo seguinte demonstra várias formas de enviar argumentos para um params parâmetro.
public static void ParamsModifierExample(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
System.Console.Write(list[i] + " ");
}
System.Console.WriteLine();
}
public static void ParamsModifierObjectExample(params object[] list)
{
for (int i = 0; i < list.Length; i++)
{
System.Console.Write(list[i] + " ");
}
System.Console.WriteLine();
}
public static void TryParamsCalls()
{
// You can send a comma-separated list of arguments of the
// specified type.
ParamsModifierExample(1, 2, 3, 4);
ParamsModifierObjectExample(1, 'a', "test");
// A params parameter accepts zero or more arguments.
// The following calling statement displays only a blank line.
ParamsModifierObjectExample();
// An array argument can be passed, as long as the array
// type matches the parameter type of the method being called.
int[] myIntArray = { 5, 6, 7, 8, 9 };
ParamsModifierExample(myIntArray);
object[] myObjArray = { 2, 'b', "test", "again" };
ParamsModifierObjectExample(myObjArray);
// The following call causes a compiler error because the object
// array cannot be converted into an integer array.
//ParamsModifierExample(myObjArray);
// The following call does not cause an error, but the entire
// integer array becomes the first element of the params array.
ParamsModifierObjectExample(myIntArray);
}
/*
Output:
1 2 3 4
1 a test
5 6 7 8 9
2 b test again
System.Int32[]
*/
A resolução de sobrecarga pode causar ambiguidade quando o argumento para um params parâmetro é um tipo de coleção. O tipo de coleção do argumento deve ser convertível para o tipo de coleção do parâmetro. Quando sobrecargas diferentes fornecem melhores conversões para esse parâmetro, esse método pode ser melhor. No entanto, se o argumento para o params parâmetro for elementos discretos ou ausentes, todas as sobrecargas com params diferentes tipos de parâmetros serão iguais para esse parâmetro.
Para obter mais informações, consulte a seção sobre listas de argumentos na Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.