Referência necessária erro somente ao usar o LINQ

9

Eu tenho 3 projetos / montagens C #, A, B e C. Referencias B Referencias A, C B

Em A:

using System.Collections.Generic;

namespace A
{
    public class Dict : Dictionary<string, object> {}
    public class Options: Dict {}
}

Em B:

using System.Collections.Generic;
using A;

namespace B
{
    public class Client
    {
        public void M(IDictionary<string, string> d)
        {
            var dict = d.ToDict<Options>();
        }
    }

    public static class Extensions
    {
        public static T ToDict<T>(this IDictionary<string, string> dictionary)
           where T : Dict, new()
        {
            return new T();
        }
    }
}

Em C:

using System.Collections.Generic;
using B;

namespace C
{
    public class Worker
    {
        public void M()
        {
            var client = new Client();
            var d = new Dictionary<string, string> { { "k", "v" } };
            var strings = new [] { "one", "two" }; // never used
            client.M(d);
        }
    }
}

Isso tudo compila.

Se eu importar o namespace System.Linq no Project C e adicionar a linha strings.Select(s => s); (ou qualquer método LINQ) antes da chamada para client.M() , recebo um erro do compilador:

  

O tipo 'A.Dict' é definido em um assembly que não é referenciado.   Você deve adicionar uma referência ao assembly 'A, Version = 1.0.0.0,   Culture = neutral, PublicKeyToken = nulo '.

Tornar a Extensions class internal ou movê-la para um namespace diferente impede o erro.

Como B deveria estar envolvendo A e escondendo seus detalhes de C, é errado deixar o método de extensão ser público. Mas eu não entendo porque isso só é escolhido pelo compilador quando o LINQ é inserido.

A presença de pelo menos um método de extensão faz o compilador se comportar de maneira um pouco diferente?

    
por Graham Clark 16.10.2015 в 11:56
fonte

1 resposta

2

Adicionar qualquer método não resolvido acionará esse erro.

Não me lembro onde li isso, mas o compilador C # (VS2013) interromperá a resolução do método de extensão quando encontrar um método de não extensão correspondente. Você pode verificar isso adicionando o seguinte código no projeto C.

public static class Extensions
{
    public static void M(this Client c, IDictionary<string, string> d)
    {
        return;
    }
}

Não causa nenhum erro!

Quando um método NÃO é resolvido com o método de não extensão (por exemplo, adicione "abc".Foo() para causar um erro do compilador), agora o compilador C # começa a varrer os métodos de extensão. Quando verifica B.Extensions.ToDict , não sabe o que é Dict . No entanto, os metadados do assembly B informam o compilador de A.Dict , então você vê o erro.

    
por qxg 16.10.2015 / 13:30
fonte