2010-08-11 5 views
3

run-time généré les questions suivantes:Sélectionner un nouvel objet en tant que paramètre tout en conservant son type

// select a subset of the DataTable 
var subset = DataTable.Where(...).Select(row => new 
{ 
    Id = Convert.ToInt32(row["Id"]), 
    Name = row["Name"].ToString(), 
    Email = row["Email"].ToString() 
}); 

// or create a new object 
var subset = new { 
    Id = 1, 
    Name = "something random", 
    Email = "[email protected]" 
}; 

Est-il possible d'utiliser la variable sous-ensemble en tant que paramètre à une méthode, sans qu'il soit jeter comme une plaine Object? Pouvez-vous en quelque sorte porter le type généré automatiquement de la variable? J'essaie d'éviter de créer de nouvelles classes chaque fois que je veux passer des sous-ensembles LINQ à des méthodes.

Les approches génériques aléatoires sont les bienvenues.

Répondre

0

Voici ce que je suis venu avec ...


méthode d'extension sur l'objet:

public static class ObjectExtensions 
{ 
    /// <summary> 
    /// Cast Object to anonymous type. 
    /// E.G.: new Object().ToAnonymousType(new { Property = new Type() }); 
    /// </summary> 
    public static T ToAnonymousType<T>(this Object o, T t) 
    { 
     return (T)o; 
    } 
} 

Utilisation:

public void HandleAnonymousTypeAsParameter(Object o) 
{ 
    var anonymousType = o.ToAnonymousType(new 
    { 
     Id = new Int32(), 
     Foo = new String(), 
     Bar = new String() 
    }); 


    // ... You can do this in even less characters: 
    var anonymousType = o.ToAnonymousType(new { Id = 0, Foo = "", Bar = "" }); 
} 


HandleAnonymousTypeAsParameter(new 
{ 
    Id = 1, 
    Foo = "foo", 
    Bar = "bar" 
}); 


Crédits va à John Skeet et Thomas P

2

Non, transmettre des types anonymes n'est généralement pas une bonne idée car vous perdez les informations de type *. Vous devriez créer un type concret et l'utiliser à la place.

var subset = DataTable.Where(...).Select(row => new SomeType 
{ 
    Id = Convert.ToInt32(row["Id"]), 
    Name = row["Name"].ToString(), 
    Email = row["Email"].ToString() 
}); 

vous pouvez également utiliser le type Tuple si vous utilisez .NET 4. Ceci est un moyen simple de créer des types et encore obtenir un certain type -sécurité « jetables ».


* En fait there is a workaround, mais je considère qu'il est un bidouille laid et conseillerait que vous ne le faites pas.

1

Vous pouvez utiliser une méthode générique:

public static void Foo<T>(T item) 
{ 
    // Do whatever 
} 

Alors si vous appelez

Foo(subset); 

le compilateur déduira T pour vous. Que ce soit ou non aide vous est une autre question ... cela dépend de ce que la méthode est destinée à faire. Il est évident que Foo ne peut pas se référer à Id, Name, Email etc.

En général, si plusieurs méthodes devraient connaître les mêmes membres, vous devez utiliser un type nommé. Le cas habituel pour les passer à des méthodes génériques est l'endroit où la méthode ne se soucie pas du type impliqué, comme dans LINQ.

J'ai demandé à C# 5 de créer des types ayant les mêmes caractéristiques que les types anonymes (immutabilité, égalité, génération de code de hachage, ToString dumping) mais pour les types nommés simples. Nous verrons si cela se produit réellement ...

2

Si j'ai besoin de faire cela, j'utilise l'option de refactoring "Remplacer le type anonyme avec la classe nommée" de resharper. Ensuite, vous avez un type approprié nommé pour exposer sur l'API, et vous n'avez pas eu à faire de travail. Cela vous donne également des options pour le créer immuable (comme les types anonymes) ou mutable, imbriqué vs top-niveau, etc

BTW, je ne recommande pas struct ici (à partir de la question).

Une autre option consiste à passer le comportement en la méthode - c'est-à-direun Action<int,string,string> callback - faire quelque chose comme:

foreach(item in query) callback(item); 

Cependant, je ne l'aime pas car il est pas évident qu'il ya une erreur probable:

DoSomething(args, (id, email, name) => Email(To: email, Subject: name)); 

(l'erreur étant qu'il devrait probablement être (id, name, email), si vous voyez ce que je veux dire)

0

Les types anonymes ne fournissent pas beaucoup d'aide en dehors du contexte où ils ont été créés.

Si vous devez passer un type anonyme à une méthode, que ce soit cette méthode est très générique comme (exemple)

void PrintAllObjectProperties(object obj); 

sorcière vous utiliser la réflexion pour faire le travail, ou que vous faites quelque chose de mal.

Questions connexes