Esta es una muy buena pregunta, ya que he visto a varios desarrolladores de C ++ escribir un terrible código C #.
Es mejor no pensar en C # como "C ++ con una sintaxis más agradable". Son diferentes idiomas que requieren diferentes enfoques en su pensamiento. C ++ te obliga a pensar constantemente en lo que harán la CPU y la memoria. C # no es así. C # está específicamente diseñado para que no esté pensando en la CPU y la memoria y, en cambio, esté pensando en el dominio comercial para el que está escribiendo .
Un ejemplo de esto que he visto es que a muchos desarrolladores de C ++ les gustará usar bucles porque son más rápidos que foreach. Esto suele ser una mala idea en C # porque restringe los posibles tipos de la colección que se repite (y, por lo tanto, la reutilización y flexibilidad del código).
Creo que la mejor manera de reajustar de C ++ a C # es intentar abordar la codificación desde una perspectiva diferente. Al principio, esto será difícil, ya que a lo largo de los años estará completamente acostumbrado a usar el hilo "qué están haciendo la CPU y la memoria" en su cerebro para filtrar el código que escribe. Pero en C #, debería pensar en las relaciones entre los objetos en el dominio empresarial. "Qué quiero hacer" en lugar de "qué está haciendo la computadora".
Si desea hacer algo a todo en una lista de objetos, en lugar de escribir un bucle for en la lista, cree un método que tome un IEnumerable<MyObject>
y use un foreach
bucle.
Tus ejemplos específicos:
Controlar la vida útil de los recursos que requieren limpieza determinista (como archivos). Esto es fácil de usar, pero ¿cómo usarlo correctamente cuando se transfiere la propiedad del recurso [... entre hilos]? En C ++, simplemente usaría punteros compartidos y dejaría que se encargue de la 'recolección de basura' en el momento adecuado.
Nunca debe hacer esto en C # (particularmente entre hilos). Si necesita hacer algo en un archivo, hágalo en un lugar a la vez. Está bien (y, de hecho, es una buena práctica) escribir una clase de contenedor que administre el recurso no administrado que se pasa entre sus clases, pero no intente pasar un archivo entre subprocesos y haga que las clases separadas lo escriban / lean / cierren / abran. No comparta la propiedad de los recursos no administrados. Use el Dispose
patrón para lidiar con la limpieza.
Constante luchando con funciones primordiales para genéricos específicos (me encantan cosas como la especialización parcial de plantilla en C ++). ¿Debo abandonar cualquier intento de hacer una programación genérica en C #? ¿Quizás los genéricos son limitados a propósito y no es C # -ish usarlos excepto para un dominio específico de problemas?
Los genéricos en C # están diseñados para ser genéricos. Las especializaciones de genéricos deben ser manejadas por clases derivadas. ¿Por qué debería un List<T>
comportamiento diferente si es un List<int>
o un List<string>
? Todas las operaciones en List<T>
son genéricas para aplicar a cualquiera List<T>
. Si desea cambiar el comportamiento del .Add
método en a List<string>
, cree una clase derivada MySpecializedStringCollection : List<string>
o una clase compuesta MySpecializedStringCollection : IList<string>
que utilice el genérico internamente pero que haga las cosas de manera diferente. Esto te ayuda a evitar violar el Principio de sustitución de Liskov y atornillar a los demás que usan tu clase.
Funcionalidad tipo macro. Si bien generalmente es una mala idea, para algunos dominios de problemas no hay otra solución alternativa (por ejemplo, evaluación condicional de una declaración, como con los registros que solo deberían ir a las versiones de depuración). No tenerlos significa que necesito poner más if (condición) {...} repetitivo y todavía no es igual en términos de desencadenar efectos secundarios.
Como han dicho otros, puede usar comandos de preprocesador para hacer esto. Los atributos son aún mejores. En general, los atributos son la mejor manera de manejar cosas que no son funcionalidades "centrales" para una clase.
En resumen, al escribir C #, tenga en cuenta que debe pensar por completo en el dominio empresarial y no en la CPU y la memoria. Puede optimizar más adelante si es necesario , pero su código debe reflejar las relaciones entre los principios comerciales que está tratando de mapear.
C#
para generar otro código. Puede leer unaCSV
o unaXML
o qué archivo tiene como entrada y generar unaC#
o unSQL
archivo. Esto puede ser más poderoso que usar macros funcionales.