Prendi un array di qualsiasi tipo di valore come parametro formale
-
05-09-2019 - |
Domanda
Mi piacerebbe poter dichiarare una funzione come
void foo(<any value type>[] data){}
in C# 2.0.Se lo dichiaro come
void foo(ValueType[] data){}
viene compilato, ma poi gli elementi in data[] vengono trattati come se derivassero da object
, per esempio.Non posso dire qualcosa del genere
fixed (void* pData = data){}
Vorrei evitare di prendere void* come parametro: voglio solo essere in grado di accettare qualsiasi array di tipo valore e quindi eseguire operazioni non gestite su di esso.
ETA:Inoltre, questo ha lo stesso problema:
public static unsafe void foo<T>(T[] data) where T:struct{
fixed(void *p = data){}
}
nel caso te lo stessi chiedendo.Risolto il problema con gli errori perché viene trattato come un tipo gestito: CS0208 non può dichiarare un puntatore a un tipo gestito.Vedere "mm" di seguito.Penso che abbia ragione...probabilmente semplicemente non è possibile farlo.
Soluzione
Non penso che questo sia possibile usando C#.Le strutture non ereditano (anche se in modo approssimativo) da System.ValueType fino a dopo la fase di compilazione, quindi non è possibile abbinare la firma del metodo di Foo tramite polimorfismo.Anche i generici sono disponibili in base alle specifiche della lingua:
"Un tipo non gestito è qualsiasi tipo che non sia un tipo di riferimento, a parametro-tipo, o un tipo struct generico e non contiene campi il cui tipo non sia un tipo non gestito."
Ecco perché non puoi prendere l'indirizzo di T[] indipendentemente dal vincolo della struttura.
Potresti dichiarare un tipo struct (ad esempio Bar) come argomento di Foo, compilare il codice e modificare la firma del metodo a livello IL:
.method private hidebysig static void Foo(valuetype [mscorlib]System.ValueType[] args) cil managed
E poi anche la chiamata:
IL_0020: call void ConsoleApplication1.Program::Foo(valuetype [mscorlib]System.ValueType[])
Anche se sono riuscito a eseguire il programma risultante, non so che tipo di effetti collaterali abbia.Inoltre, anche se potessi fare riferimento alla funzione modificata, non saresti in grado di chiamarla da C# perché ancora una volta le strutture non ereditano da System.ValueType fino a dopo la compilazione, quindi la firma del metodo non corrisponderebbe.
Altri suggerimenti
public void foo<T>(params T[] args) where T : struct {
}
public void SomeMethod() {
foo(1, 2, 3, 4);
}
Non dovresti inserire il parametro generico perché il compilatore rileverà il tipo dal primo parametro di foo.
Funzionerebbe:
public static void foo(System.Array data)
{
}
static void Main(string[] args)
{
foo(new int[10]);
}
Non impone che l'array sia un array di tipi di valore, ma funzionerebbe.