¿Cómo puedo predeterminar un parámetro a Guid.Empty en C#?
Deseo decir:
public void Problem(Guid optional = Guid.Empty)
{
}
Pero el compilador se queja de que Guid.Empty no es una constante de tiempo de compilación.
Como no deseo cambiar la API, no puedo usar:
Nullable<Guid>
Solución
Puedes usar new Guid()
en su lugar
public void Problem(Guid optional = new Guid())
{
// when called without parameters this will be true
var guidIsEmpty = optional == Guid.Empty;
}
También puedes usardefault(Guid)
default(Guid)
También funcionará exactamente como new Guid()
.
Debido a que Guid es un tipo de valor, no un tipo de referencia, default(Guid)
no es igual a null
, por ejemplo, sino que equivale a llamar al constructor predeterminado.
Lo que significa que esto:
public void Problem(Guid optional = default(Guid))
{
// when called without parameters this will be true
var guidIsEmpty = optional == Guid.Empty;
}
Es exactamente igual que el ejemplo original.
Explicación
¿Por qué no Guid.Empty
funcionó?
La razón por la que recibe el error es porque Empty
se define como:
public static readonly Guid Empty;
Entonces, es una variable, no una constante (definida como static readonly
no como const
). El compilador solo puede tener valores conocidos por el compilador como valores predeterminados de los parámetros del método (no conocidos solo en tiempo de ejecución).
La causa principal es que no puedes tener un const
of any struct
, a diferencia enum
de por ejemplo. Si lo intentas, no se compilará.
La razón, una vez más, es que struct
no es un tipo primitivo.
Para obtener una lista de todos los tipos primitivos en .NET, consulte http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(tenga en cuenta que enum
generalmente hereda int
, que es un primitivo)
¡ Pero new Guid()
tampoco es una constante!
No digo que necesite una constante. Necesita algo que pueda decidirse en tiempo de compilación. Empty
es un campo, por lo que su valor no se conoce en tiempo de compilación (solo al comienzo del tiempo de ejecución).
El valor del parámetro predeterminado debe conocerse en el momento de la compilación, que puede ser un const
valor o algo definido usando una característica de C# que hace que el valor se conozca en el momento de la compilación, como default(Guid)
o new Guid()
(que se decide en el momento de la compilación para struct
s ya que no se puede modificar el struct
constructor en código).
Si bien puede proporcionar default
o new
fácilmente, no puede proporcionar un const
(porque no es un tipo primitivo o enum
como se explicó anteriormente). Entonces, nuevamente, no digo que el parámetro opcional en sí necesite una constante, pero un valor conocido por el compilador.
Guid.Empty
es equivalente a new Guid()
, que es equivalente a default(Guid)
. Entonces puedes usar:
public void Problem(Guid optional = default(Guid))
o
public void Problem(Guid optional = new Guid())
Tenga en cuenta que el new Foo()
valor sólo es aplicable cuando:
- Realmente estás llamando al constructor sin parámetros.
Foo
es un tipo de valor
En otras palabras, cuando el compilador sabe que en realidad es solo el valor predeterminado para el tipo :)
(Curiosamente, estoy 99,9% seguro de que no llamará a ningún new Foo()
constructor personalizado que haya creado. No puede crear dicho constructor en un tipo de valor en C#, pero puede hacerlo en IL).
Puede utilizar la default(Foo)
opción para cualquier tipo.
¿No puedes usar:
default ( Guid )
?
La respuesta aceptada no funciona en ASP.NET MVC y provoca este error de tiempo de ejecución:
[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....
En su lugar, puede hacer lo siguiente:
public void Problem(Guid? optional)
{
if (optional == null)
{
optional = new Guid();
}
}