C'è un modo per fare qualcosa di simile in C#?C'è un modo per fare qualcosa di simile in C#?
public void DoSomething(string parameterA, int parameterB)
{
}
var parameters = ("someValue", 5);
DoSomething(parameters);
C'è un modo per fare qualcosa di simile in C#?C'è un modo per fare qualcosa di simile in C#?
public void DoSomething(string parameterA, int parameterB)
{
}
var parameters = ("someValue", 5);
DoSomething(parameters);
Vicino, ma sfortunatamente solo con oggetto (in modo da ottenere un sacco di boxe/unboxing)
public void DoSomething(params object[] parameters)
{
}
var parameters = new object[]{"someValue", 5};
DoSomething(parameters); // this way works
DoSomething("someValue", 5); // so does this way
+1 per essere il più vicino possibile senza ricorrere al riflesso (o delegare l'invocazione). – stakx
Pensavo avesse detto che il requisito non era quello di cambiare la firma del metodo? Ha anche messo quel requisito in grassetto, lol, quindi segna questo come la risposta! – AaronLS
@AaronLS: Sì, ma questo è l'unico modo, anche se non è perfetto ... –
no - questo non è possibile.
È possibile richiamare attraverso la riflessione, ma che ti incorrere in un certo overhead:
using System;
using System.Reflection;
namespace SO2744885
{
class Program
{
public void DoSomething(string parameterA, int parameterB)
{
Console.Out.WriteLine(parameterA + ": " + parameterB);
}
static void Main(string[] args)
{
var parameters = new object[] { "someValue", 5 };
Program p = new Program();
MethodInfo mi = typeof(Program).GetMethod("DoSomething");
mi.Invoke(p, parameters);
}
}
}
Naturalmente, se è possibile modificare la firma del metodo di prendere una matrice, che sarà il lavoro pure, ma che sembrerà peggio, secondo me.
Non potresti fare semplicemente "Azione
* gah *, sì, questa è una soluzione migliore! lunga giornata, troppo poco caffè, yaddayaddayadda. Per favore, rispondi alle risposte degli spenditori. –
Se sono tutti dello stesso tipo, sì, si può fare qualcosa in questo senso:
public void Print(params string[] args) {
foreach (string arg in args) {
Console.WriteLine(arg);
}
}
// ...
Print("apple", "banana");
Print("apple", "banana", "cherry");
Print("apple", "banana", "cherry", "doughnut");
Altrimenti no, non è possibile espandere i parametri in posizione in quel modo senza utilizzare il riflesso. C# non ha l'equivalente di Ruby splat operator.
Si può fare questo (NET 4.0):
var parameters = Tuple.Create("someValue", 5);
DoSomething(parameters.Item1, parameter.Item2);
Penso che questa risposta manchi il punto. Questo sarebbe più vicino a ciò che è stato chiesto se la funzione 'DoSomething' accetterebbe la ** tupla ** e la" decomprimi "attraverso i parametri originali. (Ma C# non ha questa caratteristica.) – stakx
Sono d'accordo - questo non risolve il problema (per quanto interessante possa essere). –
@stakx: L'aggiunta di questa "funzionalità" è abbastanza semplice utilizzando un metodo di estensione, però. Dai un'occhiata alla risposta di Henrik. –
Non c'è bisogno di utilizzare la riflessione se primo negozio come un delegato, ma richiede una forte dichiarazione del delegato.
public void DoSomething(string parameterA, int parameterB)
{
Console.WriteLine(parameterA+" : "+parameterB);
}
void Main()
{
var parameters = new object[]{"someValue", 5};
Action<string,int> func=DoSomething;
func.DynamicInvoke(parameters);
}
... e si può dimenticare il tipo di compilazione/controllo di integrità dell'elenco dei parametri. Probabilmente una brutta cosa.
"var" rappresenta solo un tipo particolare, è effettivamente una scorciatoia per scrivere un nome di tipo. In quanto sopra non stai specificando alcun tipo. L'unico modo per farlo è quello di fare una classe parametro per rappresentare gli ingressi alla rinfusa ...
public void DoSomething(Parameters param)
{
...
}
var param = new Parameters("someValue", 5);
DoSomething(param);
... ma questo è solo andare a essere utile in determinate circostanze. È possibile creare più costruttori di parametri per rappresentare diverse disposizioni di parametri, ma la funzione che si sta chiamando richiederà solo UN input: l'oggetto Parameters. Quindi con questo stai davvero minando la capacità di sovraccaricare una funzione.
Quindi, in breve, no. =)
si può fare:
public void DoSomething(string parameterA, int parameterB)
{
}
var func = (Action)(() => DoSomething("someValue", 5));
func();
Haha, mi piace: 'var func = (Azione) (...)'. Un fan della disapprovazione, vero? –
@Dan Tao cosa c'è di così divertente? – Andrey
Hai un 'Action', che hai chiamato' func', e lo hai dichiarato con 'var'. Per me è come scrivere 'var float = (double) 2.5;' ... OK, OK, forse non è così divertente. Ma tu * potresti aver * appena scritto 'Action action =() => DoSomething (" someValue ", 5);' –
Forse in questo modo è più "pulito":
// standard method calling
DoSomething("Johny", 5);
// since C# 4.0 you can used "named parameters"
DoSomething(name: "Johny", number: 5);
// calling with parameter's "container"
DoSomething(new DoSomethingParameters("Johny", 5));
// calling with parameter's "container"
DoSomething(new DoSomethingParameters{ Name = "Johny", Number = 5 });
// calling with callback for parameters initialization
DoSomething(p => { p.Name = "Johny"; p.Number = 5; });
// overload of DoSomething method with callback, which initialize parameters
public void DoSomething(Action<DoSomethingParameters> init) {
var p = new DoSomethingParameters();
init(p);
DoSomething(p);
}
// overload of DoSomething method for calling with simple parameters
public void DoSomething(string name, int number) {
var p = new DoSomethingParameters(name, number);
DoSomething(p);
}
// the "main executive" method which is "doing the work"
// all posible parameters are specified as members of DoSomethingParameters object
public void DoSomething(DoSomethingParameters p) { /* ... */ }
// specify all parameters for DoSomething method
public class DoSomethingParameters {
public string Name;
public int Number;
public DoSomethingParameters() { }
public DoSomethingParameters(string name, int number) {
this.Name = name;
this.Number = number;
}
}
Bello, aggiungi anche qualche testo esplicativo :) –
@Filip: ok, come desideri :) – TcKs
Non come commenti !! ;) –
Che ne dite di questo.NET 4 (per il gusto della curiosità)
public void DoSomething(string parameterA, int parameterB)
{
}
public void Helper(dynamic parameter)
{
DoSomething(parameter.Parameter1, parameter.Parameter2);
}
var parameters = new {Parameter1="lifeUniverseEverything", Parameter2=42};
Helper(parameters);
Ispirato dalla risposta di Steven:
static public void Execute<T1, T2>(this Tuple<T1, T2> parameters, Action<T1, T2> action)
{
action(parameters.Item1, parameters.Item2);
}
var parameters = Tuple.Create("someValue", 5);
parameters.Execute(DoSomething);
Stavo per suggerire la stessa cosa. Tranne, penso che abbia più senso eseguire "Esegui" un metodo di estensione su "Azione", vero? Quindi: '((Action
+1 Molto bello. – Steven
Se non si desidera cambiare la firma del metodo perché non dichiarare un nuovo metodo con la firma appropriata e usalo come proxy Come
public void DoSomething(string parameterA, int parameterB)
{
// Original do Something
}
public void DoSomething(object[] parameters)
{
// some contract check whether the parameters array has actually a good signature
DoSomething(parameters[0] as string,(parameters[1] as int?).Value);
}
var parameters = new object[]{"someValue", 5};
DoSomething(parameters);
Si può anche provare alcune delle cose LinFu.Reflection prevede, come tardiva. Con essa è possibile fare qualcosa di simile:
var dosomethingobject = new ObjectThatHasTheDoSomething();
DynamicObject dynamic = new DynamicObject(dosomethingobject);
var parameters = new object[]{"someValue", 5};
dynamic.Methods["DoSomething"](parameters);
Per questo è necessario che il metodo DoSomething
è all'interno di un oggetto.
Non oggi, no. Al momento stiamo prototipando esattamente questa caratteristica per una possibile futura versione ipotetica di C#.
Se è possibile fornire un motivo davvero eccezionale per cui si desidera questa funzionalità, ciò potrebbe essere un punto per riuscire a farlo uscire dalla prototipazione e in una possibile futura release ipotetica. Qual è il tuo fantastico scenario che motiva questa funzione?
(Ricordate, le speculazioni di Eric su possibili future versioni ipotetiche di C# sono per scopi di intrattenimento e non devono essere interpretate come promesse che mai ci sarà un tale rilascio o che avrà un particolare set di funzionalità.)
+1 per la fine :) – RCIX
I secondo che up-voto lol. –
Mi piace la risposta di Henrik, tranne che impone una sintassi un po 'strana: i parametri chiamano un metodo su se stessi. Lo farei al contrario. L'unico problema con questo approccio è che ti fa espressamente lanciare un metodo a un delegato.
Comunque, ecco l'idea di base:
// wrapped code to prevent horizontal overflow
public static void Execute<T1, T2>
(this Action<T1, T2> action, Tuple<T1, T2> parameters) {
action(parameters.Item1, parameters.Item2);
}
E così via (per ulteriori T
s).
Usage:
var parameters = Tuple.Create("Hi", 10);
Action<string, int> action = DoSomething;
action.Execute(parameters);
Si può anche facilmente fare questo con un valore di ritorno:
// wrapped code to prevent horizontal overflow
public static TResult Return<T1, T2, TResult>
(this Func<T1, T2, TResult> func, Tuple<T1, T2> parameters) {
return func(parameters.Item1, parameters.Item2);
}
E così via.
Vorrei anche far notare che solo perché non si è su .NET 4.0, ciò non significa che non si possa facilmente implementare il proprio tipo Tuple<T1, T2, ...>
.
Solo curioso, ha senso? – Alex
In realtà si ...? –
Non riesco davvero ad aggiungere più di quanto sia già stato aggiunto dalle altre risposte, ma sono solo curioso di sapere perché vuoi farlo. Non intendo niente di negativo, è solo quando vedo le persone fare qualcosa fuori dall'ordinario (come questo), non posso fare a meno di chiedermi perché stanno prendendo l'approccio che sono. – senfo