que - Sintaxis de diamante en C#
programa en c++ que haga un rombo (3)
No, no hay nada como la sintaxis del diamante en C #. Lo más cerca que podrías venir sería tener algo como esto:
public static class Lists
{
public static List<T> NewList<T>(List<T> ignored)
{
return new List<T>();
}
}
Entonces:
public MyClass()
{
ProtoTypes = Lists.NewList(ProtoTypes);
}
Eso solo usa la inferencia de tipo genérico normal para los métodos para obtener T
Tenga en cuenta que el valor del parámetro se ignora por completo; es solo el tipo de tiempo de compilación lo que es importante.
Personalmente creo que esto es bastante feo, y solo usaría el constructor directamente. Si cambia el tipo de ProtoTypes
el compilador detectará la diferencia y no tardará mucho en solucionarlo ...
EDITAR: Dos alternativas a considerar:
Un método similar, pero con un parámetro de
out
:public static class Lists { public static void NewList<T>(out List<T> list) { list = new List<T>(); } } ... Lists.NewList(out ProtoTypes);
El mismo método, pero como método de extensión, con el nombre
New
:public static class Lists { public static List<T> New<T>(this List<T> list) { return new List<T>(); } } ... ProtoTypes = ProtoTypes.New();
Prefiero el primer acercamiento a cualquiera de estos :)
Java 7 ahora tiene esta "sintaxis de diamante" donde puedo hacer cosas como ArrayList<int> = new ArrayList<>();
Me pregunto si C # tiene una sintaxis similar que puedo aprovechar.
Por ejemplo, tengo esta parte de una clase:
class MyClass
{
public List<double[][]> Prototypes; // each prototype is a array of array of doubles
public MyClass()
{
Prototypes = new List<double[][]>; // I''d rather do List<>, in case I change the representation of a prototype later
}
}
¿Alguien sabe si esto es posible? De ser así, ¿cómo podría utilizarlo?
Como dijo Jon Skeet y Eric Lippert hizo una copia de seguridad, los constructores de clases genéricas en C # no pueden inferir sus tipos a partir de sus parámetros o el tipo de la variable a la que se asigna la construcción. El patrón de referencia cuando este tipo de comportamiento es útil suele ser un método de fábrica genérico estático, que puede inferir su propio tipo genérico de aquellos de sus parámetros. Tuple.Create()
es un ejemplo; proporciónele cualquier lista de parámetros hasta 8 y creará una tupla genérica fuertemente tipada con esos parámetros como campos de datos. Sin embargo, esto no funciona bien en su caso.
Cuando la variable sea local, considere hacerlo al revés; use la inferencia de tipo de variable, a través de la palabra clave var
:
var Prototypes = new List<double[][]>();
Así es como el equipo de C # decidió reducir el tipeo al crear instancias de variables. Los locales se crean, y cambian, con mucha más frecuencia que las variables de instancia, y este enfoque hace que el código C # se parezca un poco más a JavaScript.
Como Jon mostró, es posible esconder el desorden, pero crearás más desorden en el proceso. Aquí hay otra posibilidad de usar las características de expresión de .NET 3.5 / 4.0:
public static string GetName(this Expression<Func<object>> expr)
{
if (expr.Body.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression) expr.Body).Member.Name;
//most value type lambdas will need this because creating the Expression
//from the lambda adds a conversion step.
if (expr.Body.NodeType == ExpressionType.Convert
&& ((UnaryExpression)expr.Body).Operand.NodeType
== ExpressionType.MemberAccess)
return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
.Member.Name;
throw new ArgumentException(
"Argument ''expr'' must be of the form ()=>variableName.");
}
public static void InitializeNew(this object me, params Expression<Func<T>>[] exprs)
where T:new()
{
var myType = me.GetType();
foreach(var expr in exprs)
{
var memberName = expr.GetName()
var myMember = myType.GetMember(memberName,
BindingFlags.Instance|BindingFlags.Public
|BindingFlags.NonPublic|BindingFlags.FlattenHierarchy,
MemberTypes.Field|MemberTypes.Property);
if(myMember == null)
throw new InvalidOperationException(
"Only property or field members are valid as expression parameters");
//it''d be nice to put these under some umbrella of "DataMembers",
//abstracting the GetValue/SetValue methods
if(myMember.MemberType == MemberTypes.Field)
((FieldInfo)myMember).SetValue(me, new T());
else
((PropertyInfo)myMember).SetValue(me, new T());
}
}
//usage
class MyClass
{
public List<double[][]> list1;
public List<double[][]> list2;
public MyOtherObject object1;
public MyClass()
{
this.Initialize(()=>list1, ()=>list2);
this.Initialize(()=>object1); //each call can only have parameters of one type
}
}
La implicación es obvia aquí; es más problema de lo que vale.
Para explicar por qué aparentemente solo tenía esto por ahí; lo anterior es una adaptación de un método que utilizo para arrojar ArgumentNullExceptions en base a parámetros pasados, que requiere que los valores se encapsulen dentro de Expresiones para retener los nombres de los parámetros reales del método de llamada. En esa situación, la complejidad detrás de las escenas se reduce ya que todo lo que necesito en el asistente principal es un cheque para nulo, y la complejidad adicional me ahorra mucho más de lo que gasto, permitiéndome hacer una línea de mis cheques sin valor en cada método y constructor de la base de código.
Recomiendo ReSharper como una solución a largo plazo para reducir este tipado. Cuando se conoce el tipo de un destino de asignación (como por ejemplo campos y propiedades) y se escribe = new
, ReSharper mostrará una sugerencia para el tipo del constructor y lo autocompletará si lo desea. Si luego cambias el tipo o el constructor, R # marcará la asignación como inconsistente, y puedes decirle a R # que cambie la que quieras que coincida con la otra.
Si solo desea reducir la verbosidad del código, existe una sintaxis y una sintaxis opuesta: el operador var
Antiguo: List<int> intList = new List<int>();
Nuevo: var intList = new List<int>();
Al menos usted escribe la List
una sola vez