Pergunta

Existe uma forma de forçar/limitar os tipos que são passados para os primitivos? (bool, int, string, etc.)

Agora, eu sei que você pode limitar o parâmetro de tipo genérico para um tipo ou implementação de interface através do onde cláusula.No entanto, isso não se encaixa o projeto de lei para primitivos (AFAIK), porque eles não têm todos uma base comum (além de objeto antes que alguém diz!:P).

Então, meus atuais pensamentos são apenas grãos meus dentes e fazer um grande mudar instrução e lançar um ArgumentException em caso de falha..


EDIT 1:

Só para esclarecer:

A definição de código deve estar assim:

public class MyClass<GenericType> ....

E instanciação:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

EDIT 2

@Jon Limjap - ponto Bom, e algo que eu já estava pensando..Eu tenho certeza que é um método genérico que pode ser usado para determinar se o tipo de um valor ou tipo de referência..

Isto pode ser útil em instantaneamente a remoção de um monte de objetos que eu não quero lidar com (mas, em seguida, você precisa de se preocupar com as estruturas que são utilizadas, tais como Tamanho )..Problema interessante, não?:)

Aqui está ele:

where T : struct

Tomadas de MSDN.


Estou curioso..Isso poderia ser feito .NET 3.x utilizar métodos de extensão?Criar uma interface, e implementar a interface dos métodos de extensão (que provavelmente será mais limpo do que um pouco de gordura switch).Além disso, se você precisa, em seguida, para depois se estender a qualquer leve tipos personalizados, eles também podem implementar a mesma interface, sem necessidade de alterações para a base de código.

O que vocês acham?

Triste notícia é que eu estou trabalhando no Quadro 2!!:D


EDIÇÃO 3

Isso era tão simples de seguir em Jon Limjaps Ponteiro..Tão simples, eu quase quis chorar, mas é grande porque o código funciona como um encanto!

Então aqui está o que eu fiz (que você vai rir!):

Código adicionado para a classe genérica

bool TypeValid()
{
    // Get the TypeCode from the Primitive Type
    TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));

    // All of the TypeCode Enumeration refer Primitive Types
    // with the exception of Object and Empty (Null).
    // Since I am willing to allow Null Types (at this time)
    // all we need to check for is Object!
    switch (code)
    {
        case TypeCode.Object:
            return false;
        default:
            return true;
    }
}

Em seguida, uma pequena utilidade do método para verificar o tipo e lançar uma exceção,

private void EnforcePrimitiveType()
{
    if (!TypeValid())
        throw new InvalidOperationException(
            "Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name + 
            "' - this Class is Designed to Work with Primitive Data Types Only.");
}

Tudo o que precisa ser feito é chamar EnforcePrimitiveType() nas classes de construtores.Trabalho feito!:-)

A única desvantagem, ele apenas lança uma exceção em tempo de execução (obviamente) em vez de tempo de design..Mas que não é grande coisa e poderia ser pego com utilitários como O FxCop (que não usamos no trabalho).

Agradecimentos especiais para Jon Limjap em um presente!

Foi útil?

Solução

Primitivos parecem ser especificado no TypeCode enumeração:

Talvez haja uma maneira de descobrir se um objeto contém o TypeCode enum sem ter de lançá-lo para um objeto específico ou ligue GetType() ou typeof()?

Atualização Foi bem debaixo do meu nariz.O código de exemplo não mostra isso:

static void WriteObjectInfo(object testObject)
{
    TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );

    switch( typeCode )
    {
        case TypeCode.Boolean:
            Console.WriteLine("Boolean: {0}", testObject);
            break;

        case TypeCode.Double:
            Console.WriteLine("Double: {0}", testObject);
            break;

        default:
            Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
            break;
        }
    }
}

Ele ainda é feio mudar.Mas é um bom lugar para começar!

Outras dicas

public class Class1<GenericType> where GenericType : struct
{
}

Este parecia fazer o trabalho..

Muito bonito o que o @Lars já disse:

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct

//Force T to be a reference type.
public class Class1<T> where T: class

//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

Todos os trabalhos em .NET 2, 3 e 3.5.

Se você pode tolerar usando métodos de fábrica (em vez de os construtores MyClass você pediu) você sempre pode fazer algo como isto:

class MyClass<T>
{
  private readonly T _value;

  private MyClass(T value) { _value = value; }

  public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
  public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
  // etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

Um problema aqui é que você precisa digitar MyClass<AnyTypeItDoesntMatter>.FromInt32, o que é chato.Não há uma muito boa maneira de contornar isso, se você deseja manter o privado-ness do construtor, mas aqui estão algumas soluções:

  • Criar uma classe abstrata MyClass.Fazer MyClass<T> herdam MyClass e aninhá-lo no prazo de MyClass.Mover os métodos estáticos para MyClass.Isso tudo a visibilidade de trabalho, o custo de acesso MyClass<T> como MyClass.MyClass<T>.
  • Utilização MyClass<T> como dado.Faça uma classe estática MyClass o que chama a métodos estáticos em MyClass<T> usando MyClass<AnyTypeItDoesntMatter> (provavelmente usando o tipo apropriado de cada vez, apenas para risos).
  • (Mais fácil, mas certamente estranho) Faça um resumo do tipo de MyClass que herda de MyClass<AnyTypeItDoesntMatter>.(Para concreto, vamos dizer que MyClass<int>.) Porque você pode chamar métodos estáticos definidos em uma classe base, através do nome de uma classe derivada, agora você pode usar MyClass.FromString.

Isto dá a você a verificação estática à custa de mais de escrever.

Se você está feliz com a dinâmica de verificar, gostaria de usar alguma variação no TypeCode solução acima.

@Roberto, Enum's vai escorregar através dos TypeValid função de como é TypeCode é Integer.Eu atualizei a função também para verificar se há Enum.

Private Function TypeValid() As Boolean
    Dim g As Type = GetType(T)
    Dim code As TypeCode = Type.GetTypeCode(g)

    ' All of the TypeCode Enumeration refer Primitive Types
    ' with the exception of Object and Empty (Nothing).
    ' Note: must also catch Enum as its type is Integer.
    Select Case code
        Case TypeCode.Object
            Return False
        Case Else
            ' Enum's TypeCode is Integer, so check BaseType
            If g.BaseType Is GetType(System.Enum) Then
                Return False
            Else
                Return True
            End If
    End Select
End Function

Você pode simplificar o EnforcePrimitiveType método usando typeof(PrimitiveDataType).IsPrimitive propriedade.Eu estou faltando alguma coisa?

Usar um personalizado O FxCop regra de que as bandeiras uso indesejável de MyClass<>.

Ter um desafio semelhante, eu queria saber como vocês se sentem em relação a IConvertible interface.Ele permite que o solicitante requer, e você pode estender com suas próprias implementações.

Exemplo:

    public class MyClass<TKey>
    where TKey : IConvertible
{
    // class intentionally abbreviated
}

Eu estou pensando sobre isso como uma solução, tudo bem que muitos dos sugeriu que fosse parte da minha seleção também.

A minha preocupação é - no entanto - é enganosa por potenciais desenvolvedores usando sua classe?

Felicidades e obrigado.

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