Option Strict causing compiling error within LINQ statement (implicit conversion 'Object' to 'Control')

Estamos convirtiendo actualmente un proyecto VB a C#, y comenzando por habilitar Option Strict. Cuando está activada, la siguiente línea genera un error:

Dim visiblePanelCount As Integer = (From c As Control In pnl_AdminPageLinks.Controls 
                                     Where TypeOf (c) Is Panel AndAlso c.Visible 
                                     Select c).Count()

La línea roja está en As Control con el error:

BC30512 Option Strict Sobre las conversiones implícitas de 'Objeto' a 'Control '

Entiendo lo que significa el error, pero no puedo entender dónde es el tipo de Object está siendo creado (como creo que .Controls es una colección de tipo Control).

Un segundo ejemplo que tiene menos sentido para mí es "Objeto a DataRow" mismo error bajo As DataRow en esta línea:

Return (From dr As DataRow In MyDataTable.Rows ' error on As DataRow
        Select New MyClass() With {
            .Id = Convert.ToInt32(dr.Item("Id")),
            .UserId = Convert.ToInt32(dr.Item("UserId"))
        }).ToList()

Convierto el código a C# que generó la misma lógica, así que no entienda VB. El problema subyacente de Net.

Pregunta hecha hace 3 años, 4 meses, 28 días - Por codealchemyf00f


3 Respuestas:

  • Recuerde que LINQ está basado en el genérico IEnumerable(Of T) interfaz y eso Controls la colección, a pesar de contener sólo controles, no implementa IEnumerable(Of Control). Sólo implementa IEnumerable así, cuando se enumera, proporciona un Object sólo referencia. La manera de salir de IEnumerable a IEnumerable(Of T) está con el Cast(Of T) método:

    Dim visiblePanelCount = (From c In pnl_AdminPageLinks.Controls.Cast(Of Control)()
                             Where TypeOf (c) Is Panel AndAlso c.Visible 
                             Select c).Count()
    

    Puedes eliminar el tipo de cheque llamando OfType(Of T) también, que también burla los Cast(Of T) llamada:

    Dim visiblePanelCount = (From c In pnl_AdminPageLinks.Controls.OfType(Of Panel)()
                             Where c.Visible 
                             Select c).Count()
    

    También puede omitir Select cláusula en VB si usted está simplemente seleccionando el elemento de consulta original:

    Dim visiblePanelCount = (From c In pnl_AdminPageLinks.Controls.OfType(Of Panel)()
                             Where c.Visible).Count()
    

    Dado que Count método también filtrará, usted puede simplificar esa consulta aún más:

    Dim visiblePanelCount = pnl_AdminPageLinks.Controls.OfType(Of Panel)().Count(Function(p) p.Visible)
    

    Respondida el Dec 17, 2020 a las 11:55 - por scriptwarrior

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás experimentando se debe a cómo Option Strict en VB.NET trata las conversiones implícitas de tipos. Cuando Option Strict está habilitado, todas las conversiones implícitas deben ser explícitas para evitar pérdidas de datos inadvertidas.

    En tu primer ejemplo, el problema está en la parte de la declaración de la variable en la expresión LINQ. Cuando usas From c As Control In pnl_AdminPageLinks.Controls, el tipo de datos de c se infiere como Object en lugar de Control debido a cómo LINQ trata las colecciones genéricas. Por lo tanto, al intentar usar As Control en esa declaración, estás intentando convertir un Object a un Control, lo cual es una conversión implícita que no es válida cuando Option Strict está habilitado.

    Una forma de resolver esto es cambiar la identificación del tipo de c dentro de la expresión LINQ para evitar la conversión implícita. Puedes lograrlo cast o convertir el objeto c en un Control de manera explícita, de la siguiente manera:

    csharp
    Dim visiblePanelCount As Integer = (From c In pnl_AdminPageLinks.Controls.Cast(Of Control)()
                                         Where TypeOf (c) Is Panel AndAlso c.Visible 
                                         Select c).Count()
    

    En cuanto al segundo ejemplo, el problema es similar. Debes cambiar la identificación del tipo de dr a DataRow dentro de la expresión LINQ para evitar la conversión implícita. Puedes hacerlo de la siguiente manera:

    csharp
    Return (From dr In MyDataTable.Rows.Cast(Of DataRow)()
            Select New MyClass() With {
                .Id = Convert.ToInt32(dr.Item("Id")),
                .UserId = Convert.ToInt32(dr.Item("UserId"))
            }).ToList()
    

    Al hacer estos cambios, deberías poder compilar tu código sin errores con Option Strict habilitado en VB.NET.

    Respondida el Dec 18, 2020 a las 11:55 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Problema 1: Conversión de Object a Control

    En la siguiente línea:

    vb
    Dim visiblePanelCount As Integer = (From c As Control In 
    

    El tipo de c se infiere como Object. Esto se debe a que la cláusula From en una consulta LINQ devuelve un conjunto de objetos anónimos. Para resolver este problema, puedes especificar explícitamente el tipo de c como Control:

    vb
    Dim visiblePanelCount As Integer = (From c As Control In 
    

    Problema 2: Conversión de Object a DataRow

    En la siguiente línea:

    vb
    Return (From dr As DataRow In 
    

    El tipo de dr también se infiere como Object. Esto se debe a que la propiedad Rows de una DataTable devuelve una colección de DataRow anónimos. Para resolver este problema, puedes especificar explícitamente el tipo de dr como DataRow:

    vb
    Return (From dr As DataRow In 
    

    Solución de C

    Las conversiones de tipo explícitas en C

    se pueden lograr utilizando el operador as. Aquí tienes las líneas conver neumáticos:

    Problema 1:

    csharp
    int visiblePanelCount = (from Control c in panel.Controls 
    

    Problema 2:

    csharp
    return (from DataRow 
    

    Respondida el Dec 18, 2020 a las 11:59 - por Gemini

    Votos positivos: 0 | Votos negativos: 0