Pergunta

Eu tenho um c # struct onde eu preciso proibir chamando o construtor sem argumentos sobre ele.

MyStruct a;
/// init a by members   // OK
MyStruct b = MyStruct.Fact(args); // OK, inits by memebers

MyStruct s = new MyStruct(); // can't have that

Estou fazendo isso principalmente para força de valores explicet para todos os membros que não existem valores padrão válidos e todos os membros devem ter valores válidos.

Em C ++ isso seria fácil, adicione um construtor privado, mas c # não permite isso.

Existe uma maneira de impedir que o anterior?

Eu realmente preciso aplicar usando uma fábrica para prevenir todas as chamadas de construtor público iria funcionar tão bem.


discloser completa: para evitar uma dependência mono, o c # aplicativo está sendo traduzidos automaticamente para D, onde new Struct() resulta em um ponteiro e isso é sujando as coisas para mim. No entanto, esta questão é relevante apesar de que tão simplesmente ignorá-lo.

Foi útil?

Solução

Você não pode. Todas as estruturas têm um construtor sem parâmetros pública por definição em C #. (No CLR quase nenhum deles fazem, mas eles sempre podem agir como se eles têm.) Consulte esta questão para porque você pode 't definir seus próprios construtores sem parâmetros em estruturas (em C #, de qualquer maneira).

Na verdade, você pode impedir que esta declaração se você está feliz para escrever o seu tipo de valor em IL. Eu verifiquei apenas, e se você se certificar de que o seu tipo de valor só tem um construtor sem parâmetros, e torná-lo interno, você não será capaz de escrever MyStruct ms = new MyStruct(); Mas isso não impede que:

MyStruct[] array = new MyStruct[1];
MyStruct ms = array[0];

que funciona em torno da nova restrição - por isso realmente não comprar nada. Isso é muito bom realmente, como andar em IL seria confuso.

Você tem certeza que quer realmente estar escrevendo um struct em primeiro lugar? Isso é quase nunca é uma boa idéia.

Outras dicas

Você não pode.

Todos os valores em um struct deve ser inicializado em tempo de construção, e não há nenhuma maneira de fazer isso fora do construtor.

O que exatamente você está tentando realizar, ao fazer isso? Estruturas são tipos de valor, então você vai ter um "novo" struct para a maioria das operações. Vai ser muito difícil de aplicar os tipos de restrições que você usaria uma fábrica para em um struct.

Qualquer um pode criar um struct a qualquer momento sem chamar um construtor, contanto que eles têm acesso para a estrutura. Pense nisso desta maneira:

Se você criar uma matriz de objetos com 1000 elementos, todos eles se inicializado para nulo, de modo nenhum construtor for chamado.

Com estruturas, não existe tal coisa como nulo. Se você criar uma matriz com 1000 DateTime objetos, todos eles são inicializados para zero, o que equivale a DateTime.Min. Os designers do tempo de execução escolheu para torná-lo assim que você poderia criar uma matriz de estruturas sem chamar os tempos construtor N -. Um desempenho atingido muitas pessoas não percebem estava lá

O seu ideia fábrica é uma boa, embora. Será que atender às suas necessidades para criar uma interface e expor isso, mas fazer o struct privada ou interna? Isso é quase tão perto como você vai conseguir.

Coloque-o em sua própria montagem e ter o MyStruct () sem os args como Interno (Friend in VB). Ter a fábrica no mesmo assembly como MyStruct (), mas com um acessor público.

Agora, a fábrica pode acessar a qualquer args MyStruct, mas nada ligando de fora da montagem deve usar a fábrica.

Edit: Meu ruim, eu não levou em conta que este é um struct. Você não pode fazer isso com um struct, apenas com uma classe - neste caso, a minha afirmação anterior significa

.

Você poderia fazer um struct que detecta se ele está em um estado padrão inicializado, e depois fazer algo adequado, nesse caso. Saí da fábrica, mas um construtor também poderia ser uma fábrica adequada no comum, caso simples.

É um monte de código clichê. Desde que você use D, você pode estar pensando a mesma coisa que eu sou, "eu desejo C # tinha mixins de modelo."

Exemplo:

using System;

namespace CrazyStruct
{
    public struct MyStruct
    {
        private readonly int _height;
        private readonly bool _init; // Will be 'false' using default(MyStruct).

        /// <summary>
        /// Height in centimeters.
        /// </summary>
        public int Height
        {
            get
            {
                if (!_init)
                {
                    // Alternatively, could have the preferred default value set here.
                    // _height = 200; // cm
                    // _heightInit = true;
                    throw new InvalidOperationException("Height has not been initialized.");
                }
                return _height;
            }
            // No set:  immutable-ish.
        }

        private MyStruct(int height)
        {
            _height = height;
            _init = true;
        }

        public static MyStruct Factory(int height)
        {
            return new MyStruct(height);
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            MyStruct my = MyStruct.Factory(195);
            Console.WriteLine("My height is {0} cm.", my.Height);
            try
            {
                var array = new MyStruct[1];
                var ms = array[0];
                Console.WriteLine("My height is not {0} cm.", ms.Height);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught the expected exception: {0}.", ex);
            }
            Console.ReadKey();
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top