Pregunta

He oído que la gente del estado que los Generadores de Código y plantillas T4 no debe ser utilizado.La lógica detrás de esto es que si se genera un código con un generador, a continuación, hay una mejor manera más eficiente para generar el código a través de los medicamentos genéricos y de plantillas.

Mientras que un poco de acuerdo con esta declaración de arriba, yo realmente no han encontrado maneras eficaces para construir plantillas que pueden decir por ejemplo crear una instancia de sí mismos.En otras palabras nunca puedo hacer :

return new T();

Además, si quiero generar código basado en valores de base de datos he encontrado que el uso de Microsoft.SqlServer.Management.SMO en conjunción con plantillas T4 ha sido maravillosa en la generación de cantidades masivas de código sin tener que copiar / pegar o usar resharper.

Muchos de los problemas que he encontrado con los Genéricos también lo es que para mi sorpresa hay un montón de desarrolladores que no los entienden.Cuando hago examinar genéricos para una solución, hay momentos donde es complicado, debido a que C# indica que no puede hacer algo que puede parecer lógico en mi mente.

¿Cuáles son tus pensamientos?¿Prefiere construir un generador, o ¿prefiere el uso de los medicamentos genéricos?También, ¿hasta dónde puede genéricos ir?Sé que una cantidad decente acerca de los genéricos, pero hay trampas y las trampas que siempre me encuentro con que me causa para recurrir a una plantilla T4.

¿Cuál es la más adecuada manera de manejar los escenarios donde se necesita una gran cantidad de flexibilidad?Ah, y como un bono a esta pregunta, ¿cuáles son buenos recursos en C# y los medicamentos Genéricos?

¿Fue útil?

Solución

Puede hacer nuevo T (); si lo hace

public class Meh<T>
  where T : new()
{
  public static T CreateOne()
  {
    return new T();
  }
}

En cuanto a los generadores de códigos. Yo uso una cada día sin ningún problema. Estoy usando uno ahora, de hecho: -)

Los genéricos resolver un problema, generadores de códigos resolver otro. Por ejemplo, la creación de un modelo de negocio utilizando un editor UML y luego generar sus clases con el código de persistencia como lo hago todo el tiempo usando esta herramienta no se puede lograr con los genéricos, ya que cada clase persistente es completamente diferente.

En cuanto a una buena fuente de los genéricos. La mejor tiene que ser libro Jon Skeet por supuesto! : -)

Otros consejos

Como el autor de la T4, he tenido que defender a esta pregunta unas cuantas veces como puedas imaginar :-)

Mi creencia es que en su mejor generación de código es un paso en el camino a la producción de valor equivalente el uso de bibliotecas reutilizables.

Como muchos otros han dicho, el concepto clave para mantener SECO es nunca, jamás, el cambio de código generado de forma manual, sino la preservación de su capacidad de regenerarse cuando el origen de los cambios en los metadatos o encuentra un error en el generador de código.En ese punto, el código generado tiene muchas de las características de código objeto, y que no se quede en copiar/pegar tipo de problemas.

En general, es mucho menos esfuerzo para producir un parametrizada generador de código (especialmente con plantilla basada en sistemas) que es para diseñar correctamente una alta calidad de la base de la biblioteca que obtiene el coste del uso al mismo nivel, por lo que es una forma rápida de obtener el valor de la coherencia y eliminar la repetición de los errores.

Sin embargo, todavía creo que el sistema de acabado con más frecuencia mejorarse menos el total del código.Si nada más, la huella de su memoria casi siempre ser significativamente menor (aunque la gente tiende a pensar que los medicamentos genéricos como libre de costo en este sentido, que ciertamente no lo son).

Si he dado cuenta de algunos de valor de uso de un generador de código, a continuación, esto a menudo, usted compra algo de tiempo o de dinero o de buena voluntad de invertir en la extracción de una biblioteca de la que genera el código base.Usted puede luego gradualmente se reestructura el generador de código de destino de la nueva biblioteca y esperemos que generan mucho menos código.Enjuague y repita.

Un interesante contrapunto que ha sido hecho para mí y que viene en este hilo es que los ricos, complejos, paramétrico de que las bibliotecas no son la cosa más fácil en términos de la curva de aprendizaje, especialmente para aquellos que no están profundamente inmersos en la plataforma.Siguiendo con la generación de código a simple marcos básicos puede producir detallado código, pero a menudo puede ser bastante sencillo y fácil de leer.

Por supuesto, que usted tiene un montón de varianza y muy rica, la parametrización en el generador, que sólo podría estar operando en la complejidad de un producto para la complejidad en sus plantillas.Este es un camino fácil de deslizarse dentro y puede hacer mantenimiento al igual que un gran dolor de cabeza - mirar hacia fuera para eso.

Generación de código no está mal y no huele! La clave es generar el código correcto en el momento correcto. Creo que la T4 es grande - sólo lo uso de vez en cuando, pero cuando lo hago es muy útil. Decir, sin condiciones, que la generación de código es malo es incondicionalmente loco!

Me parece generadores de código son bien siempre y cuando la generación de código es parte de su proceso de construcción normal, en lugar de algo que se ejecuta una vez y luego mantener su producción. Añado esta advertencia porque si sólo tiene que utilizar el generador de código una vez y desechar los datos que lo creó, sólo estás automáticamente la creación de una violación masiva y mantenimiento SECO dolor de cabeza; mientras que la generación del código cada vez que efectivamente significa que todo lo que está utilizando para hacer el generador es el código fuente real, y los archivos generados son sólo etapas intermedias de compilación que se debe sobre todo pasar por alto.

Lex y Yacc son ejemplos clásicos de herramientas de le permiten especificar la funcionalidad de una manera eficiente y generar código eficiente de la misma. Tratando de hacer su trabajo con la mano que alargará el tiempo de desarrollo y probablemente producir código menos eficiente y menos legible. Y aunque ciertamente se podría incorporar algo así como lex y yacc directamente en su código y hacer su trabajo en tiempo de ejecución en lugar de en tiempo de compilación, que sin duda añadiría complejidad considerable a su código y reducir la velocidad. Si realmente necesita cambiar su especificación en tiempo de ejecución que podría valer la pena, pero en la mayoría de los casos normales usando lex / yacc para generar código para que en tiempo de compilación es una gran victoria.

Un buen porcentaje de lo que es en Visual Studio 2010 no sería posible sin la generación de código. Entity Framework no sería posible. El simple acto de arrastrar y soltar un control sobre una forma no sería posible, ni sería Linq. Decir que no debe utilizarse la generación de código es extraño que tantos utilizarlo sin siquiera pensar en ello.

Tal vez es un poco duro, pero para mí la generación de código huele.

Esa generación de código se utiliza significa que hay numerosos principios comunes subyacentes que pueden expresarse en un "No te repitas" de la moda. Se puede tomar un poco más de tiempo, pero es satisfactorio cuando se termina con las clases que sólo contienen los bits que realmente cambiar, basado en una infraestructura que contiene la mecánica.

En cuanto a los genéricos ... no, yo no tengo demasiados problemas con ella. La única cosa que actualmente no trabaja está diciendo que

List<Animal> a = new List<Animal>();
List<object> o = a;

Pero incluso eso será posible en la próxima versión de C #.

Más código significa una mayor complejidad. Más complejidad significa más lugares para los insectos que se esconden, lo que significa ciclos fijos más largos, que a su vez se traduce en mayores costes a lo largo del proyecto.

Siempre que sea posible, prefiero minimizar la cantidad de código para proporcionar una funcionalidad equivalente; Lo ideal sería que el uso dinámico (programación) se acerca más que la generación de código. Reflexión, atributos, aspectos genéricos y proporcionar un montón de opciones para una estrategia SECO, dejando generación como último recurso.

La generación de código es para mí una solución para muchos problemas encontrados en el lenguaje, marcos, etc. Ellos no son malos por sí mismos, yo diría que es muy, muy mal (es decir, el mal) para liberar un lenguaje (C #) y el marco de la cual te obliga a copiar y pegar (permuta de las propiedades, eventos de activación, la falta de macros) o utilizar los números mágicos (WPF vinculante).

Por lo tanto, lloro, pero los utilizo, porque tengo que hacerlo.

He usado T4 para la generación de código y también los genéricos. Ambos son buenos, tienen sus ventajas y desventajas, y son adecuados para diferentes propósitos.

En mi caso, utilizo T4 para generar Entidades, DAL y BLL basado en un esquema de base de datos. Sin embargo, DAL y BLL referencia a una mini-ORM he construido, sobre la base de los genéricos y la reflexión. Así que creo que se les puede utilizar al lado del otro, siempre y cuando mantenga el control y mantenerlo pequeño y simple.

T4 genera código estático, mientras que los genéricos es dinámico. Si utiliza los genéricos, se utiliza la reflexión que se dice que es menos eficiente que la solución "modificable". Por supuesto se puede almacenar en caché los resultados de reflexión.

En cuanto a "devolver nueva T ();", utilizo Métodos dinámicos como esto:

public class ObjectCreateMethod
    {
    delegate object MethodInvoker();
    MethodInvoker methodHandler = null;

    public ObjectCreateMethod(Type type)
    {
        CreateMethod(type.GetConstructor(Type.EmptyTypes));
    }

    public ObjectCreateMethod(ConstructorInfo target)
    {
        CreateMethod(target);
    }

    void CreateMethod(ConstructorInfo target)
    {
        DynamicMethod dynamic = new DynamicMethod(string.Empty,
                    typeof(object),
                    new Type[0],
                    target.DeclaringType);
        ILGenerator il = dynamic.GetILGenerator();
        il.DeclareLocal(target.DeclaringType);
        il.Emit(OpCodes.Newobj, target);
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ret);

        methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
    }

    public object CreateInstance()
    {
        return methodHandler();
    }
}

A continuación, la llamo así:

ObjectCreateMethod _MetodoDinamico = new ObjectCreateMethod(info.PropertyType);
object _nuevaEntidad = _MetodoDinamico.CreateInstance();

Los genéricos y generación de código son dos cosas diferentes. En algunos casos se puede utilizar medicamentos genéricos en lugar de la generación de código y para aquellos que creen que debería. Por la otra generación de código de los casos es una herramienta poderosa.

Para todos los casos en los que sólo hay que generar código basado en alguna entrada de datos, generación de código es el camino a seguir. La más obvia, pero de ninguna manera el único ejemplo es el editor de formularios en Visual Studio. Aquí, la entrada es el diseñador de los datos y la salida es el código. En este caso los genéricos es realmente no ayuda en absoluto, pero es muy agradable que VS simplemente genera el código basado en el diseño de interfaz gráfica de usuario.

Los generadores de código podría considerarse un olor código que indica una falla o falta de funcionalidad en el langauge objetivo.

Por ejemplo, mientras que se ha dicho aquí que "los objetos que persisten, no se puede generalizar", sería mejor pensar en él como "Objetos en C # que persisten automáticamente sus datos no se pueden generalizar en C #", porque yo sí puede, en Python mediante el uso de diversos métodos.

El enfoque Python podría, sin embargo, ser emulado en idiomas estáticas a través del uso del operador [] (method_name como cadena), que o bien devuelve un funtor o una cadena, dependiendo de los requisitos. Por desgracia, esa solución no siempre es el caso, y devolver un funtor puede ser un inconveniente.

El punto que estoy haciendo es que los generadores de código indican una falla en un idioma elegido a que se refiera al proporcionar un especializada sintaxis más conveniente para el problema específico que nos ocupa.

El tipo de copiar / pegar del código generado (como hacen ORM) también puede ser muy útil ...

Usted puede crear su base de datos, y luego tener el ORM generar una copia de la base de datos que la definición expresada en su idioma preferido.

La ventaja viene cuando cambie su definición original (la base de datos), pulse la compilación y el ORM (si tiene una buena) puede re-genera una copia de la definición. Ahora todas las referencias a su base de datos se puede comprobar por el comprobador de tipos compiladores y su código fallará para compilar cuando se está utilizando tablas o columnas que ya no existen.

Piense en esto: Si llamo a un método de un par de veces en mi código, no estoy refiriendo al nombre que he dado a este método originalmente? Sigo repitiendo ese nombre una y otra vez ... Los diseñadores de lenguajes reconocido este problema y se le ocurrió "Tipo-seguridad" como la solución. La no retirada de las copias (como DRY sugiere que deberíamos hacer), pero comprobando que se realiza la corrección en su lugar.

El ORM genera el código trae la misma solución cuando se hace referencia a los nombres de tablas y columnas. La no retirada de las copias / referencias, pero con lo que la definición de base de datos a su lengua (de tipo seguro) donde se puede hacer referencia a las clases y propiedades en su lugar. Junto con la comprobación de tipos compiladores, esto resuelve un problema similar de una manera similar: Garantía de errores en tiempo de compilación en lugar de los de tiempo de ejecución cuando se hace referencia a las tablas obsoletos o mal escritas (clases) o columnas (propiedades)

.

cita: En realidad no he encontrado maneras eficaces para construir plantillas que pueden decir, por ejemplo, crear una instancia de sí mismos. En otras palabras nunca puedo hacer:

volver nueva T ();

public abstract class MehBase<TSelf, TParam1, TParam2>
    where TSelf : MehBase<TSelf, TParam1, TParam2>, new()
{
    public static TSelf CreateOne()
    {
        return new TSelf();
    }
}

public class Meh<TParam1, TParam2> : MehBase<Meh<TParam1, TParam2>, TParam1, TParam2>
{
    public void Proof()
    {
        Meh<TParam1, TParam2> instanceOfSelf1 = Meh<TParam1, TParam2>.CreateOne();
        Meh<int, string> instanceOfSelf2 = Meh<int, string>.CreateOne();
    }
} 

La generación de código, como los genéricos, plantillas, y otros atajos, es una herramienta poderosa. Y al igual que con la mayoría de las herramientas de gran alcance, que amplifica la capaility de su usuario para el bien y para el mal -. Que no pueden ser separados

Así que si usted entiende su generador de código de fondo, anticipar todo lo que se va a producir, y por qué, y la intención que lo haga por razones válidas, a continuación, tienen en él. Pero no lo use (o cualquiera de la otra técnica) para llegar más allá de un lugar donde no estás a seguro hacia dónde se dirige, o cómo llegar allí.

Algunas personas piensan que, si su problema sea resuelto actual y un comportamiento implementado, ya está de oro. No siempre es obvio lo mucho costra y la opacidad de salir en su camino para la próxima desarrollador (que podría ser uno mismo.)

¿Por qué no ser capaz de copiar / pegar muy, muy rápido, que sea más aceptable?

Esa es la única justificación para la generación de código que yo pueda ver.

Aunque el generador proporciona toda la flexibilidad que necesita, usted todavía tiene que aprender a utilizar esa flexibilidad -. Que es otro nivel de aprendizaje y ensayo exigida

E incluso si se ejecuta en el tiempo cero, todavía se hincha el código.

Rodé mi propia clase de acceso a datos. Se sabe todo acerca de las conexiones, transacciones, parms procedimiento almacenado, etc, etc, y yo sólo tenía que escribir todas las cosas ADO.NET vez.

Hace ya mucho tiempo que no tenía que escribir (o incluso mirar a) cualquier cosa con un objeto de conexión en el mismo, que me costaría mucho para recordar la sintaxis improvisada.

scroll top