Valor estático general requerido por varias clases -- # camp codereview Relacionados El problema

General static value required by multiple classes


7
vote

problema

Español

Tengo un valor general llamado semilla que se requiere para varias clases. Pero esas clase no dependen de la clase que lo declaran.

  class Game {     class Settings {        public static float Seed = 1337;     } }   

y alguna clase necesita un valor de para trabajar. Tomo la clase Noise como ejemplo aquí.

  class Noise {     private static float _seed; }   

Una solución sería usar Game.Settings.Seed para conocer el valor en el ruido de la clase. Pero, ¿qué pasa si algún día decido tomar toda la clase 9988776665544334 para usarlo en otro proyecto? El código no compilará porque probablemente no haya un 99887776655544335 declarado en el otro proyecto, obviamente.

Otra forma sería establecer como campo público en la clase de ruido.

  class Noise {     public static float Seed; }   

Así que de esta manera, Game que sabe que necesita usar 9988777665544338 Clase, se establecerá semillas antes de hacer cualquier cosa con esta clase.

Pero no me gusta también, en este caso, esto se trata de un 9988776665544339 , por lo que no es realmente un problema, pero ¿qué pasa con un 99887766555443310 que necesita ser declarado, lo que significa Noise1 la clase necesita implementar una verificación sobre sí misma.

  Noise2  

Esta solución funciona pero no me complace al respecto. Para No-nulable Tipo I tiene que definir una otra variable para verificar, para una clase i nulable puedo compararla con Noise3 . Pero de todos modos, no tengo un solo parámetro y no tengo una sola clase. Estoy buscando una mejor manera de implementarlo.

Original en ingles

I have a general value called Seed which is required to multiple class. But those class aren't dependent of the class which declare it.

class Game {     class Settings {        public static float Seed = 1337;     } } 

And some class need a Seed value to work. I take the class Noise as example here.

class Noise {     private static float _seed; } 

A solution would be to use Game.Settings.Seed to know the value into the class Noise. But what if one day I decide to take all the Noise class to use it in an other project. The code won't compile because there is probably not a Game.Settings.Seed declared in the other project obviously.

A other way would be to set as public field in the Noise class.

class Noise {     public static float Seed; } 

So in this way, Game which know he need to use Noise class, will set Seed field before doing anything with this class.

But I don't like it too, in this case this is about a float, so that not really a problem, but what about an object that need to be declared, which means Noise class need to implement a verification about itself.

class Noise {      private static float _seed;     private static bool _isSeedDeclared;      public static void SetSeed(int seed){         _seed = seed;         _isSeedDeclared = true;     }      public int GetValue(int x, int z){         CheckSettings();         return computedValue; //to calculate computedValue, I need Seed value     }      private void CheckSettings(){         if(!_isSeedDeclared)             throw new Exception("You have to define Seed value.");     } } 

This solution works but I'm not pleased about it. For non-nullable type I have to define an other variable to check, for a nullable class I can compare it to null. But anyway, I don't have only one parameter and I don't have only one class. I'm looking for an better way to implement it.

  
         
         

Lista de respuestas

8
 
vote
vote
La mejor respuesta
 

Está bien, así que hay muchos en su pregunta. Intentemos y vamos a romperlo.

Pero, pero si un día decido tomar toda la clase de ruido para usarla en otro proyecto. El código no compilará porque probablemente no haya un juego.settings.seed declarado en el otro proyecto obviamente.

de lo que estás hablando aquí es desacoplando . Hay muchos tipos diferentes de acoplamiento en el diseño de software. Usted está en el camino correcto, desacoplando sus clases entre sí es una cosa muy buena para hacer por muchas razones, incluido el que ha descrito.

En este ejemplo específico, estamos tratando de desacoplar el Noise de la clase Game.Settings .

Realmente has recibido 2 opciones aquí. inyección de constructor o inyección de propiedad . Ambas opciones son válidas, pero tienen pros y contras dependiendo de sus requisitos. Cualquier otra opción es solo una variación de estos dos (por ejemplo, inyección de campo, servicio o inyección de funciones) o realmente desacoplará las cosas.

Así que de esta manera, el juego que sabe que necesita usar la clase de ruido, establecerá un campo de semillas antes de hacer algo con esta clase.

Una de las ventajas de uso de la inyección de constructores es hacer cumplir que la clase 99887766655544332 establece la semilla en la clase Noise Antes de que se pueda usar.

  _noise = new Noise(Game.Settings.Seed);   

Otra forma sería establecer como campo público en la clase de ruido.

Esta es una forma de inyección de propiedad. El inconveniente es que solo puede hacer cumplir las cosas utilizando excepciones en tiempo de ejecución. En algunos casos, tiene sentido, pero por lo que he visto, no creo que esta sea su mejor opción.

Para un tipo no anulado, tengo que definir una otra variable para verificar, para una clase anulable, puedo compararla con NULL.

En realidad, C # tiene tipos anulables por exactamente esta situación. Para que pueda convertir este código:

  private static float _seed; private static bool _isSeedDeclared;   

en esto:

  private static float? _seed;   

y cuando quieras usarlo puedes hacer algo como esto:

  if(!_seed.HasValue)     throw new Exception("You have to define Seed value.");   

Pero de todos modos, no tengo un solo parámetro y no tengo una sola clase. Estoy buscando una mejor manera de implementarlo.

Estoy de acuerdo, su pregunta es un poco más ancha que esta clase. Es más sobre el diseño general del sistema en su conjunto. La verdad es que no hay una talla única para todas las respuestas, depende.

Creo que parte del problema es el uso excesivo de static . No está realmente claro por qué la clase 9988776665544339 debe usar estática en absoluto. En particular, es probable que se encuentre con todo tipo de problemas con el uso de Estado estático global Como sospecho es el caso.

Considerariamente consideraría eliminar todo el Game.Settings0 ness de cualquier clases que no lo necesitan. Especialmente si también están teniendo en cuenta los datos compartidos. Como de costumbre, depende, pero podría sorprenderse de lo mucho que se convierten en las cosas más simples cuando soltamos esa idea.

 

Okay, so there's lots going on in your question. Let's try and break it down.

But what if one day I decide to take all the Noise class to use it in an other project. The code won't compile because there is probably not a Game.Settings.Seed declared in the other project obviously.

What you're talking about here is decoupling. There are many different types of coupling in software design. You're on the right track, decoupling your classes from each other is a very good thing to do for many reasons, including the one you've described.

In this specific example we're trying to decouple the Noise class from the Game.Settings class.

You've really only got 2 options here. Constructor injection or Property injection. Both options are valid but they have pros and cons depending on your requirements. Any other option is either just a variation of these two (e.g. field injection, service or function injection) or won't really decouple things.

So in this way, Game which know he need to use Noise class, will set Seed field before doing anything with this class.

One of the pros of using constructor injection is to enforce that the Game class sets the seed on the Noise class before it can be used.

_noise = new Noise(Game.Settings.Seed); 

A other way would be to set as public field in the Noise class.

This is a form of property injection. The downside is that you can only enforce things by using exceptions at runtime. In some cases it makes sense, but from what I've seen I don't think this is your best choice.

For non-nullable type I have to define an other variable to check, for a nullable class I can compare it to null.

Actually, C# has nullable types for exactly this situation. So you could convert this code:

private static float _seed; private static bool _isSeedDeclared; 

into this:

private static float? _seed; 

and when you want to use it you can do something like this:

if(!_seed.HasValue)     throw new Exception("You have to define Seed value."); 

But anyway, I don't have only one parameter and I don't have only one class. I'm looking for an better way to implement it.

I agree, your question is a little more broad than this one class. It's more about the overall design of the system as a whole. The truth is there's no one size fits all answer, it depends.

I believe part of the problem is the overuse of static. It's not really clear why the Noise class needs to use static at all. In particular, you're likely to run into all sorts of issues with the use of global static state as I suspect is the case.

I'd seriously consider removing all the staticness from any classes that don't need it. Especially if they're also holding shared data. As usual, it depends, but you might be surprised how much simpler things become when you let go of that idea.

 
 
 
 
10
 
vote

Si el parámetro Game.Settings11 se requiere para la clase 99887766555443312 funciona correctamente, debe ir al constructor como un parámetro como un . Si un 99887766555443313 998877766655443314 Explicando lo que está mal con el Game.Settings5 y (idealmente) lo que el valor esperado podría Parece que (por ejemplo, si hay algunas reglas de rango que tienen lugar en su dominio).

Los consumidores del Game.Settings6 tendrán que inyectar el valor adecuado (es probable que lo tome de la configuración).

 

If the seed parameter is required for the Noise class to work properly, it must go to the constructor as a required parameter. If an invalid seed passed to the constructor, it should throw an ArgumentException explaining what's wrong with the seed and (ideally) what the expected value could look like (e.g. if there are some range rules take place in your domain).

Consumers of the Noise class will have to inject the proper value (likely taking it from the settings).

 
 
7
 
vote

Estás haciendo Settings Todo mal.

Sé que no me crees, pero tú eres. He estado trabajando en un (muy) proyecto a largo plazo (3+ años) con un sistema de tipo 'Configuración', y mi solución fue muy voluminosa, pero crea mucho menos trabajo más tarde.

Ni siquiera puedo decirlo donde planea usar Seed en la clase 9988776655544332 , ¿en qué se activa como semilla? todo? Necesita agrupar cosas en categorías para que pueda crear una separación de responsabilidades (SRP) y mantener las cosas que están relacionadas juntas .

.

Lo primero que hice es crear una clase 99887766655443333 que tiene los sistemas de configuración común en él:

  [DataContract] public class BaseConfiguration {     [DataMember]     public NetworkConfiguration NetworkConfiguration { get; set; }      [DataMember]     public LoggingConfiguration LoggingConfiguration { get; set; }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public static string ConfigurationFile { get; set; } = "Config.xml";      public void Save<T>()     {         Save<T>(this);     }      public static void Save<T>(BaseConfiguration config)     {         DataContractSerializer dcs = new DataContractSerializer(typeof(T));          using (FileStream fs = new FileStream(ConfigurationFile, FileMode.Create))         using (XmlWriter writer = XmlDictionaryWriter.CreateTextWriter(fs))         {             dcs.WriteObject(writer, config);         }     }      public static T Load<T>()     {         DataContractSerializer dcs = new DataContractSerializer(typeof(T));          using (FileStream fs = new FileStream(ConfigurationFile, FileMode.OpenOrCreate))         using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()))         {             return (T)dcs.ReadObject(reader);         }     } }   

Luego, hay dos clases que se derivan de esto, un 9988776655544335 y un ServerConfiguration :

  [DataContract] public class ClientConfiguration : BaseConfiguration {     [DataMember]     public GraphicsConfiguration GraphicsConfiguration { get; set; } }  [DataContract] public class ServerConfiguration : BaseConfiguration {     [DataMember]     public WorldConfiguration WorldConfiguration { get; set; }      [DataMember]     public SqlConfiguration SqlConfiguration { get; set; } }   

Luego, tiene la configuración real en cada Configuration Tipo:

  [DataContract] public class WorldConfiguration {     /// <summary>     /// The number of <see cref="Chunk"/>s wide that the <see cref="World"/> is.     /// </summary>     [DataMember]     public ushort WorldChunkWidth { get; set; }      /// <summary>     /// The number of <see cref="Chunk"/>s high that the <see cref="World"/> is.     /// </summary>     [DataMember]     public ushort WorldChunkHeight { get; set; }      /// <summary>     /// The total number of <see cref="Chunk"/>s in the <see cref="World"/>.     /// </summary>     [DataMember]     public uint WorldChunkSize { get; set; }      /// <summary>     /// The number of <see cref="Tiles"/> wide each <see cref="Chunk"/> is.     /// </summary>     [DataMember]     public ushort ChunkWidth { get; set; }      /// <summary>     /// The number of <see cref="Tiles"/> high each <see cref="Chunk"/> is.     /// </summary>     [DataMember]     public ushort ChunkHeight { get; set; }      /// <summary>     /// The number of pixels wide each of the <see cref="Tiles"/>"/> are.     /// </summary>     [DataMember]     public byte TileWidth { get; set; }      /// <summary>     /// The number of pixels high each of the <see cref="Tiles"/>"/> are.     /// </summary>     [DataMember]     public byte TileHeight { get; set; }      [DataMember]     public string ChunkFolder { get; set; }      [DataMember]     public string PlayerFolder { get; set; }      [DataMember]     public string PlayerTable { get; set; }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Rectangle TileBounds => new Rectangle(0, 0, WorldChunkWidth * TileBounds.Width, WorldChunkHeight * TileBounds.Height);      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Rectangle PixelBounds => new Rectangle(0, 0, WorldChunkWidth * PixelBounds.Width, WorldChunkHeight * PixelBounds.Height);      public WorldConfiguration()     {         WorldChunkWidth = 256;         WorldChunkHeight = 256;         ChunkWidth = 256;         ChunkHeight = 256;         TileWidth = 32;         TileHeight = 32;          ChunkFolder = @"WorldChunks";         PlayerFolder = @"WorldPlayers";         PlayerTable = @"dbo.Players";     } }  [DataContract] public class LoggingConfiguration {     [DataMember]     public string Folder { get; set; }      [DataMember]     public int MaxFileSize { get; set; } }  [DataContract] public class GraphicsConfiguration {     [DataMember]     public bool VSync { get; set; } = true;      [DataMember]     public bool IsFixedTimeStep { get; set; } = false;      [DataMember]     public bool FullScreen { get; set; } = false;      [DataMember]     public byte[] ResolutionBytes     {         get { return Resolution.GetBytes(); }         set         {             var sz = new Size();             sz.FromBytes(value);             Resolution = sz;         }     }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Size Resolution { get; set; } }   

etc. No entraré en detalle en todos ellos, pero obtienes la foto. Tenga en cuenta que Seed0 es un tipo de 99887766555443311 Yo mismo, no es el .NET incorporado, puede cortar eso y 99887766555443312 Si quieres intentar usar esto y construir tu propia alternativa.

Ahora, finalmente llegamos al punto en que queremos usar el 99887766655443313 tipos:

  Seed4  

(este bit es feo, pero solo es para fines de prueba).

luego para cargarlo:

  Seed5  

Luego, finalmente, pasa Seed6 o Seed7 , 99887766555443318 , etc. alrededor como desee.


Finalmente, llegamos a Seed9 :

¿Por qué todo está en este Settings0 ? ¿Qué sucede si quiero dos variaciones con diferentes semillas? No puedes hacer eso con tu implementación.

solo Mark cosas estáticas que son estados universales. Es decir, algo que hay absolutamente ninguna razón para querer tener diferentes estados.

En su caso, Settings2 no cumple con ese criterio.

  Settings3  

aún mejor: realice una interfaz para que pueda tener diferentes tipos diferentes de ruido:

  Settings4  

Luego implementarlo:

  Settings5  

Luego, , cualquier objeto / método que necesita un 99887766655443326 puede tomar un 998877766655443327 , lo que significa que puede proporcionar diferentes tipos de ruido si usted Necesitar. (Hago esto con mucha frecuencia con el registro.)

 

You're doing Settings all wrong.

I know you don't believe me, but you are. I've been working on a (very) long-term project (3+ years) with a 'settings' type system, and my solution was very bulky, but creates a lot less work later.

I can't even tell where you plan on using Seed in the Settings class, what does it act as a seed for? Everything? You need to group things into categories so that you can create a separation of responsibilities (SRP), and keep things that are related together.

The first thing I did is create a BaseConfiguration class that has the common settings systems in it:

[DataContract] public class BaseConfiguration {     [DataMember]     public NetworkConfiguration NetworkConfiguration { get; set; }      [DataMember]     public LoggingConfiguration LoggingConfiguration { get; set; }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public static string ConfigurationFile { get; set; } = "Config.xml";      public void Save<T>()     {         Save<T>(this);     }      public static void Save<T>(BaseConfiguration config)     {         DataContractSerializer dcs = new DataContractSerializer(typeof(T));          using (FileStream fs = new FileStream(ConfigurationFile, FileMode.Create))         using (XmlWriter writer = XmlDictionaryWriter.CreateTextWriter(fs))         {             dcs.WriteObject(writer, config);         }     }      public static T Load<T>()     {         DataContractSerializer dcs = new DataContractSerializer(typeof(T));          using (FileStream fs = new FileStream(ConfigurationFile, FileMode.OpenOrCreate))         using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()))         {             return (T)dcs.ReadObject(reader);         }     } } 

Then, there are two classes that derive from this, a ClientConfiguration and a ServerConfiguration:

[DataContract] public class ClientConfiguration : BaseConfiguration {     [DataMember]     public GraphicsConfiguration GraphicsConfiguration { get; set; } }  [DataContract] public class ServerConfiguration : BaseConfiguration {     [DataMember]     public WorldConfiguration WorldConfiguration { get; set; }      [DataMember]     public SqlConfiguration SqlConfiguration { get; set; } } 

Then you have the actual settings in each Configuration type:

[DataContract] public class WorldConfiguration {     /// <summary>     /// The number of <see cref="Chunk"/>s wide that the <see cref="World"/> is.     /// </summary>     [DataMember]     public ushort WorldChunkWidth { get; set; }      /// <summary>     /// The number of <see cref="Chunk"/>s high that the <see cref="World"/> is.     /// </summary>     [DataMember]     public ushort WorldChunkHeight { get; set; }      /// <summary>     /// The total number of <see cref="Chunk"/>s in the <see cref="World"/>.     /// </summary>     [DataMember]     public uint WorldChunkSize { get; set; }      /// <summary>     /// The number of <see cref="Tiles"/> wide each <see cref="Chunk"/> is.     /// </summary>     [DataMember]     public ushort ChunkWidth { get; set; }      /// <summary>     /// The number of <see cref="Tiles"/> high each <see cref="Chunk"/> is.     /// </summary>     [DataMember]     public ushort ChunkHeight { get; set; }      /// <summary>     /// The number of pixels wide each of the <see cref="Tiles"/>"/> are.     /// </summary>     [DataMember]     public byte TileWidth { get; set; }      /// <summary>     /// The number of pixels high each of the <see cref="Tiles"/>"/> are.     /// </summary>     [DataMember]     public byte TileHeight { get; set; }      [DataMember]     public string ChunkFolder { get; set; }      [DataMember]     public string PlayerFolder { get; set; }      [DataMember]     public string PlayerTable { get; set; }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Rectangle TileBounds => new Rectangle(0, 0, WorldChunkWidth * TileBounds.Width, WorldChunkHeight * TileBounds.Height);      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Rectangle PixelBounds => new Rectangle(0, 0, WorldChunkWidth * PixelBounds.Width, WorldChunkHeight * PixelBounds.Height);      public WorldConfiguration()     {         WorldChunkWidth = 256;         WorldChunkHeight = 256;         ChunkWidth = 256;         ChunkHeight = 256;         TileWidth = 32;         TileHeight = 32;          ChunkFolder = @"World\Chunks";         PlayerFolder = @"World\Players";         PlayerTable = @"dbo.Players";     } }  [DataContract] public class LoggingConfiguration {     [DataMember]     public string Folder { get; set; }      [DataMember]     public int MaxFileSize { get; set; } }  [DataContract] public class GraphicsConfiguration {     [DataMember]     public bool VSync { get; set; } = true;      [DataMember]     public bool IsFixedTimeStep { get; set; } = false;      [DataMember]     public bool FullScreen { get; set; } = false;      [DataMember]     public byte[] ResolutionBytes     {         get { return Resolution.GetBytes(); }         set         {             var sz = new Size();             sz.FromBytes(value);             Resolution = sz;         }     }      [XmlIgnore]     [ScriptIgnore]     [IgnoreDataMember]     public Size Resolution { get; set; } } 

Etc. I won't go into detail on all of them, but you get the picture. Do note that Resolution is a custom Size type I built myself, not the built-in .NET ones, you can cut that and ResolutionBytes out if you want to try to use this and build your own alternative.

Now eventually we come to the point where we want to use the Configuration types:

BaseConfiguration.ConfigurationFile = @"Config\Config.xml"; ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.LoggingConfiguration = new LoggingConfiguration(); clientConfiguration.LoggingConfiguration.Folder = "Log"; clientConfiguration.LoggingConfiguration.MaxFileSize = 16 * 1024 * 1024; clientConfiguration.NetworkConfiguration = new NetworkConfiguration(); clientConfiguration.NetworkConfiguration.PeerString = "Ancients"; clientConfiguration.NetworkConfiguration.Port = 8093; clientConfiguration.NetworkConfiguration.IP = "127.0.0.1"; clientConfiguration.GraphicsConfiguration = new GraphicsConfiguration(); clientConfiguration.GraphicsConfiguration.IsFixedTimeStep = false; clientConfiguration.GraphicsConfiguration.VSync = true; clientConfiguration.GraphicsConfiguration.FullScreen = false; clientConfiguration.GraphicsConfiguration.Resolution = new Size(1024, 768); BaseConfiguration.Save<ClientConfiguration>(clientConfiguration); 

(This bit is ugly, but it's for testing purposes only.)

Then to load it:

var config = BaseConfiguration.Load<ClientConfiguration>(); 

Then finally you pass config or config.LoggingConfiguration, config.GraphicsConfiguration, etc. around as you desire.


Finally, we come to Noise:

Why is everything in this static? What happens if I want two Noise variations with different seeds? You cannot do that with your implementation.

Only mark things static that are universal states. That is, something that there is absolutely no reason to want to have different states for.

In your case, Noise does not meet that criteria.

class Noise {     private float _seed;      public Noise(float seed)     {         _seed = seed;     }      public int GetValue(int x, int z)     {         return computedValue; //to calculate computedValue, I need Seed value     } } 

Even better: make an interface so you can have different types of noise:

public interface INoise {     int GetValue(int x, int z); } 

Then implement it:

public class PerlinNoise {     private float _seed;      public PerlinNoise(float seed)     {         _seed = seed;     }      public int GetValue(int x, int z)     {         return calculatedValue;     } } 

Then any object/method that needs a Noise can just take an INoise, which means you can supply different noise-types if you need to. (I do this very frequently with logging.)

 
 
1
 
vote

Estoy justo detrás de la respuesta de Sergey Shushlyapin de hacer un constructor con los parámetros requeridos. En su código, esto significaría hacer Settings8 un parámetro requerido para el Settings9 constructor de clase.

Para ayudar a ilustrar esta respuesta, quería contribuir al proporcionarle una actualización de su propio código:

  BaseConfiguration0  

Esto se usaría, como SO

  BaseConfiguration1  

Uso Propiedades

Sin embargo, como mejora en el código anterior, me inclinaría más hacia este enfoque de usar propiedades. A medida que el uso de su código existente no proporciona manera de conocer el conocimiento del valor de la semilla fuera del BaseConfiguration2 clase.

  BaseConfiguration3  

Esto se usaría, como SO

  BaseConfiguration4  

Tómalo un paso más

También podría evitar repetir un gran código, moviendo todo lo anterior a una clase de "base", he agregado el ejemplo aquí:

Nota: que el modificador de acceso se ha cambiado a BaseConfiguration5 , pero puede cambiar este comportamiento si no desea que la clase heredada tenga acceso directo.

  BaseConfiguration6  

Luego, obtendría su clase de IT:

  BaseConfiguration8  
 

I'm right behind Sergey Shushlyapin's answer of making a constructor with required parameters. In your code, this would mean making seed a required parameter for the Noise class constructor.

To help illustrate this answer, I wanted to contribute by providing you with an update of your own code:

class Noise {      private static float _seed;      public Noise(float seed)     {         UpdateSeed(seed);     }      public void UpdateSeed(float seed){         if(seed < 0) throw new ArgumentOutOfRangeException(nameof(seed), "cannot be a negative value");          _seed = seed;     }      public int GetValue(int x, int z){         CheckSettings();         return computedValue; //to calculate computedValue, I need Seed value     } } 

This would be used, like so

Noise noise = new Noise(0);   // constructor noise.UpdateSeed(10);         // UpdateSeed method 

Use Properties

However, as an improvement upon the code above, I would lean more towards this approach of using properties. As using your existing code doesn't provide way for knowledge of the seed value outside of the Noise class.

public class Noise {     private static float _seed;      public float Seed     {         get         {             return _seed;         }         set         {             if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "must be greater than zero");             _seed = value;         }     }       public Noise(float seed)     {         this.Seed = seed;     }      ... } 

This would be used, like so

Noise noise = new Noise(0);   // constructor noise.Seed = 10;              // set float seedValue = noise.Seed; // get 

Taking it a step further

You could also avoid repeating a lot of code, by moving all of the above into a "base" class, I've added the example here:

Note: that the access modifier has been changed to protected, but you can change this behavior if you do not want the inherited class to have direct access.

public class BaseClass {     protected float _seed;      public float Seed     {         get         {             return _seed;         }         set         {             if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "must be greater than zero");             _seed = value;         }     }      public BaseClass(float seed)     {         this.Seed = seed;     } } 

Then you would derive your Noise class from it:

public class Noise : BaseClass {     public Noise(float seed) : base(seed) { } } 
 
 
0
 
vote

Solo póngalo en la configuración de la clase. Si mueve su ruido de clase en otro proyecto, deberá hacer algo de refactorización de todos modos.

 

Just put it in class Settings. If you move your class Noise in another project, you will need to do some refactoring anyway.

 
 

Relacionados problema

3  Genéricos anulables - implementando secuencialSearchst en C #  ( Nullable generics implementing sequentialsearchst in c ) 
Para fines de aprendizaje, estoy implementando cierto código de SEDEDWICK & AMP; Los algoritmos de Wayne, cuarta edición . Debido a las características del...

3  Generador de imágenes de Mandelbrot con iteración paralela  ( Mandelbrot image generator with parallel iteration ) 
Actualmente estoy tratando de optimizar esta clase que tengo para la generación fractal. La ecuación está destinada a ser conectable; He usado z => z*z + c ...

6  PRIGO DE PODER TICTACTOO EN C #  ( Command prompt tictactoe in c ) 
Escribí un juego básico de comando TIC TAC TOE juego. Quiero saber qué se puede mejorar en términos de modelado y qué errores he hecho (si corresponde). vo...

3  Mientras que el bucle usa variables adicionales, ¿se puede limpiar esto?  ( While loop uses extra variables can this be cleaned up ) 
Una pieza de mi programa permite que se utilice el bucle y la incremento de una entidad seleccionada en un bucle de tiempo en otro lugar. Aquí hay una muestra...

7  Versión LINQ del algoritmo de recocido simulado  ( Linq version of the simulated annealing algorithm ) 
Decidí intentarlo e implementar (una versión de) la recocido simulado algoritmo usando solo linq , solo para ver si pudiera. Me encantaría si alguien pudi...

1  TPL HILO FUGA Y FUGA DE MEMORIA  ( Tpl thread leak and memory leak ) 
Estoy tratando de rastrear lo que supongo que debo ser una pérdida de memoria / hilo en uno de mis programas. Mi programa usa una función para cargar un arc...

7  Colecciones vacías en caché  ( Cached empty collections ) 
A menudo necesito devolver las colecciones vacías. Uno de esos días, escribí lo siguiente para devolver una instancia en caché: public static class Array<...

0  Creación de múltiples objetos del extracto de SQL Server  ( Creating multiple objects from sql server extract ) 
He creado una solución prototipo simplificada como una especie de prueba de concepto antes de comenzar un programa más grande. Aquí están los datos de prueb...

6  ¿Está mi delegado definió la forma correcta y necesita transformarse en una mariposa bonita?  ( Is my delegate defined the right way and does it need to transform to a pretty e ) 
He leído tantos Historias de tiempo de cama e inserciones de cómo < fuertes> delegados trabajo y por qué eventos deben ser reemplazados por los delegado...

35  Demasiados bucles en la aplicación de dibujo  ( Too many loops in drawing app ) 
Tengo un método que tiene muchos bucles: #ifndef __RUNES_STRUCTURES_H #define __RUNES_STRUCTURES_H /* Runes structures. */ struct Game { char board[2...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos