Pergunta

Estou trabalhando em um serviço web C# com uma classe estática genérica que usa um tipo.Eu queria saber por que isso não compila:

Type type1 = typeof(MySnazzyType);
Assert.AreEqual(0, ConnectionPool_Accessor<type1>._pool.Count);

Dá esse erro:

O tipo ou nome do namespace 'type1' não foi encontrado (falta uma diretiva using ou uma referência assembly?)

E o ReSharper, quando passo o mouse type1 nessa segunda linha de código, diz "Tipo ou nome do namespace esperado".Bem, type1 é um tipo!É uma variável do tipo Type!Também não funciona se eu fizer:

Type type1 = typeof(MySnazzyType);
Assert.AreEqual(0, ConnectionPool_Accessor<typeof(type1)>._pool.Count);

Eu esperava atribuir meus tipos a alguns tipos diferentes Type variáveis ​​e apenas usá-las para testar as diferentes classes estáticas genéricas, em vez de digitar MySnazzyType cada vez.Alguma idéia, ou estou preso em fazer:

Assert.AreEqual(0, ConnectionPool_Accessor<MySnazzyType>._pool.Count);

Editar: esclarecer, MySnazzyType é não uma classe genérica, nem herda de uma classe genérica.A única classe genérica aqui é ConnectionPool_Accessor.

Graças ao comentário de Pavel "Essencialmente, seu problema é que C# é uma linguagem de tipo estaticamente", agora sei que Ruby me estragou.;)

Foi útil?

Solução

Em primeiro lugar, o ReSharper está realmente correto.Não é um tipo, é um variável.É verdade que é uma variável que contém o objeto de reflexão que corresponde a um tipo, mas isso não é suficiente.

Entre colchetes <...> você deve escrever o nome de um tipo, não o nome de qualquer outro identificador.

No entanto, você pode construir objetos genéricos por meio de reflexão e acessar suas propriedades, mesmo as estáticas; portanto, você deve ser capaz de reescrever o código para fazer isso. No entanto, você já olhou para o NUnit 2.5?

A partir das notas de versão mais recentes, parece que as classes de teste de unidade agora podem ser genéricas e você pode especificar com um atributo na classe de teste quais tipos serão testados.

Isso permitiria que você escrevesse algo assim (observe, eu não testei isso, apenas procurei os nomes dos novos atributos na documentação):

[TestFixture(typeof(MySnazzyType))]
[TestFixture(typeof(MyOtherSnazzyType))]
public class Tests<T>
{
    [Test]
    public void PoolCount_IsZero()
    {
        Assert.AreEqual(0, ConnectionPool_Accessor<T>._pool.Count);
    }
}

Outras dicas

Os tipos genéricos são avaliados em tempo de compilação, não em tempo de execução.Como não pode ser determinado em tempo de execução o que type1 será, esta construção não é permitida.

Na verdade, isso é o que o Resharper diz: type1 não é um tipo, é uma variável do tipo Type, (assim como poderia ser um objeto do tipo String).

O TestFixture atributo deve configurá-lo, mas só por diversão:se você quiser fazer tudo isso em tempo de execução, poderá fazê-lo usando reflexão.

Type poolType = typeof(ConnectionPool_Accessor<>);
Type snazzyType = typeof(MySnazzyType); // Or however you want to get the appropriate Type
poolType.MakeGenericType(snazzyType);

Você poderia então fazer o que quiser usando a reflexão em poolType.É claro que isso será um grande problema, a menos que você use a digitação dinâmica do C# 4.0.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top