Differenze da Py a C#

import Rhino as rh


def GetCrvs():

    go = rh.Input.Custom.GetObject()
    
    go.SetCommandPrompt("Select Object")
    
    go.Get()

    if go.CommandResult() != rh.Commands.Result.Success: return go.CommandResult()
    
    return go


unknown = GetCrvs()

print( unknown )
print( unknown.Object(0) )
print( unknown.Object(0).Curve() )
print( unknown.Object(0).Object() )
using System;
using rh = Rhino;

object GetCrvs()
{
    rh.Input.Custom.GetObject go = new rh.Input.Custom.GetObject();

    go.SetCommandPrompt("Select Object");

    go.Get();
    
    if (go.CommandResult() != rh.Commands.Result.Success) return go.CommandResult();
    
    return go;
}

var unknown = GetCrvs();

//rh.RhinoApp.WriteLine( unknown );
//rh.RhinoApp.WriteLine( unknown.Object(0) );
//rh.RhinoApp.WriteLine( unknown.Object(0).Curve() );
//rh.RhinoApp.WriteLine( unknown.Object(0).Object() );

errore del primo WriteLine evidenziandomi unknown:

Argument 1: cannot convert from ‘object’ to ‘string’

errore in tutti gli altri 3 WriteLine evidenziandomi Object(0):

‘object’ does not contain a definition for ‘Object’ and no accessible extension method ‘Object’ accepting a first argument of type ‘object’ could be found (are you missing a using directive or an assembly reference?)

cercando di convertire questo script da Py a C# sono incappato in questa situazione,
anche capendo il problema non riesco a trovare la soluzione
dal messaggio di errore unknown è un oggetto fin qui è chiaro
giustamente mi dice che non può convertire un oggetto in stringa
(anche forzando la conversione ma per ora nulla)

ora sappiamo che Py non tiene conto di nulla, qualsiasi cosa gli dai lui esegue oggetti stringe ecc
ma come in Py è possibile stampare output di quei oggetti, si dovrebbe poter fare la stessa cosa in C#?
(ovviamente usando la procedura corretta intendo)

e vabbè ma non si fa così. . .

soluzione per il primo errore:

//rh.RhinoApp.WriteLine( unknown );

Console.WriteLine(unknown);

oppure in questo modo sembri che funzioni ugualmente:

rh.RhinoApp.WriteLine( $"{unknown}" );
rh.RhinoApp.WriteLine( "{0}", unknown );
rh.RhinoApp.WriteLine( Convert.ToString(unknown) );

per gli altri 3 errori rimane lo stesso messaggio

‘object’ does not contain a definition for ‘Object’ and no accessible extension method ‘Object’ accepting a first argument of type ‘object’ could be found (are you missing a using directive or an assembly reference?)

mi sà che dev’essere indicato diversamente Object(0)

Il C# rispetta i tipi che tu dichiari.
Se dichiari che la funzione GetCrvs restituisce un object, lui il valore restituito lo considera un object.
( Questo e’ possibile dato che ogni oggetto discende da object )
Per cui quando tu in fase di stampa gli dici di eseguire il metodo Object, lui non trova nessun metodo Object appartenente all’oggetto di tipo object e ti da’ errore.

si su questo ci sono arrivato, ma comunque non ne vengo a capo

using sy = System;
using rh = Rhino;

rh.Input.Custom.GetObject GetCrvs()
{
    rh.Input.Custom.GetObject go = new rh.Input.Custom.GetObject();

    go.SetCommandPrompt("Select Object");

    go.Get();
    
    if (go.CommandResult() != rh.Commands.Result.Success) return go.CommandResult();
    
    sy.Console.WriteLine( go.ObjectCount );

    return go;
}

rh.Input.Custom.GetObject obj = GetCrvs();

inizialmente avevo anche provato in questo modo che mi sembrava corretto,
ma poi di dava problemi col return interno return go.CommandResult()

Cannot implicitly convert type ‘Rhino.Commands.Result’ to ‘Rhino.Input.Custom.GetObject’

ed avevo corretto come postato prima, ma poi proseguendo nel codice mi dava problemi col WriteLine

poi a questo punto non comprendo perché se il tipo della classe sia object vada bene per entrambi
i return, mentre la classe tipizzata come questo post per nel return intermedio mi torna errore?

Da’ problemi perche’ il tipo e’ diverso da quello dichiarato.
Se tu dichiari che una funzione restituisce una string e poi resituisci un double, lui segnala l’errore.
Qui e’ la stessa cosa.

L’ho detto sopra

Ripassa l’ereditarieta’ in C#. :wink:
Tutte le classi discendono da object, quindi ogni oggetto puo’ essere considerato di tipo object.

Se permetti un commento. :slight_smile:
Secondo me, utilizzare in C# metodi che possono restituire valori di tipi completamente diversi, come in questo caso, non e’ il modo piu’ semplice di procedere.
Quello che e’ comodo in Python puo’ essere scomodo in C#.

eeee che bella scoperta, in tutti gli esempi di C# che mi ero salvato, i return sono tutti con Result

unica eccezione è questa:

  private static Rhino.Geometry.NurbsCurve GetSpirial1()
  {
    var railStart = new Rhino.Geometry.Point3d(0, 0, 0);
    var railEnd = new Rhino.Geometry.Point3d(0, 0, 10);
    var railCurve = new Rhino.Geometry.LineCurve(railStart, railEnd);
   
    double t0 = railCurve.Domain.Min;
    double t1 = railCurve.Domain.Max;
   
    var radiusPoint = new Rhino.Geometry.Point3d(1, 0, 0);
   
    return Rhino.Geometry.NurbsCurve.CreateSpiral(railCurve, t0, t1, radiusPoint, 1, 10, 1.0, 1.0, 12);
  }

adesso vedo se ereditarietà come da te indicata va bene :+1:

e pure, quei pochi script fatti con RCommon in Py funzionano, lo stesso codice in C# non va bene
e bisogna ri-raggionarci sopra e oltre a convertirli anche apportare le opportune modifiche :triumph: :triumph:


ps comunque mi fa strana questa motodologia:

rh.Input.Custom.GetObject GetCrvs()
{
    rh.Input.Custom.GetObject go = new rh.Input.Custom.GetObject();

se io indico una classe tipizzata come vedere sopra, e la nuova istanza oggetto sempre come indicata,
nei return sia quelli intermedi che finali, mi aspetto che venga gestita sia l’oggetto ma anche il risultato.

(mio pensiero ovviamente)

Restituire Result va benissimo, ma il metodo deve restituire solo oggetti di tipo Result.
E lo deve dichiarare all’inizio.
Non e’ che un tipo sia meglio di un altro …
E’ solo che un metodo deve restituire sempre lo stesso tipo (quello che dichiari all’inizio).

Se non mischi i vari tipi tra loro non devi preoccuparti dell’ereditarieta’, almeno quando scrivi il metodo.

Non so perche’ quegli esempi resituiscano tipi diversi dalla stessa funzione … a me sembra un po’ una stranezza :smile:.
Comunque tu controlla a cosa serve restituire tipi diversi.
Potrebbe esserci un modo semplice per fare la stessa cosa senza mischiare i tipi. :slight_smile:

Non capisco bene cosa intendi, soprattutto cosa intendi con gestita.
Ma, partendo dalle istruzioni che riporti, se tu restituisci l’oggetto go va benissimo.
Pero’ non puoi restituire oggetti di un tipo diverso.

il go nel return finale si

ma questa riga, nel return intermedio non va bene
if (go.CommandResult() != rh.Commands.Result.Success) return go.CommandResult();

anche se go.CommandResult() fa parte di rh.Input.Custom.GetObject GetCrvs()

questo mi :exploding_head: :exploding_head:

eeee magari, a saperlo. se c’é di sicuro lo scoprirò. la domanda è, chissà tra quanto tempo.


come far gestire ad un Metodo il return, sia con il result che con un oggetto Input.Custom.GetObject ?

Scusa, in che senso “fa parte” ?

Per andare sul pratico … a cosa ti serve ottenere tipi diversi da quel metodo ?
Cosa ci fai ?
(Personalmente non capisco a cosa serva una cosa simile … :thinking:)

Poi se vuoi ricavare piu’ di un valore da un metodo, il modo c’e’.
Mai sentito parlare di parametri out ? :wink:

si ma usato con questo metodo: Rhino.Input.RhinoGet.GetOneObject mai usato con il Custom
(dici che sia possibile?)

se vedi il codice Py nel primo post, se il risultato non’é Success ritorna il risultato altrimenti ritorna go

non ci vedo una cosa strana, anzi un discorso abbastanza senzato

se il Metodo richiede un oggetto rh.Input.Custom.GetObject
e go equivale a new rh.Input.Custom.GetObject();
dopo aver esegito go.Get();
posso richiamare sia go.Object(0) che go.CommandResult()

come detto sopra se il Metodo richiede un oggetto rh.Input.Custom.GetObject
quindi allo stesso modo perché il return non accetta sia go.Object(0) che go.CommandResult()

Giusto, proprio quello ! :slight_smile:

Non e’ questione di RhinoCommon.
Quella e’ una feature del C#. Se scrivi tu il metodo, la usi come e quando vuoi.

Quello si vede.
Ma quello che non capisco e’ cosa ci fai con un valore che non sai nemmeno di che tipo e’.
Quando richiami quella funzione, come utilizzi il valore restituito ?

OK, allora saprai spiegarmi come utilizzi questa cosa. :slight_smile:

Il metodo non richiede nessun oggetto. Non ha parametri.
Il tipo che scrivi prima del nome del metodo e’ il tipo del valore restituito, credevo lo sapessi gia’. :wink:

E’ un oggetto di quel tipo che, per caso, in quel momento ti serve per fare i tuoi calcoli ecc. dentro a quel metodo.
E che puoi restituire dal metodo, visto che il tipo combacia.

Certo, con l’oggetto go ci fai quello che vuoi.

Non richiede niente. :slight_smile:
Restituisce un oggetto di tipo ‘Rhino.Input.Custom.GetObjet’.

Scusa, quale modo ?

Perche’, come gia’ accennato, quel metodo deve restituire solo oggetti di tipo
Rhino.Input.Custom.GetObject
Semplicemente perche’ cosi’ e’ scritto prima del nome del metodo: quello e’ il tipo da restituire.
Non ci sono altri ragionamenti.

Ovviamente il tipo da restituire lo decidi tu, e dopo averlo deciso, lo scrivi prima del nome del metodo.
E scrivi il resto dello script di conseguenza.

Se prima del nome del metodo scrivi float, allora il metodo dovra’ restituire sempre e solo valori di tipo float

Questo vale per ogni tipo, non ci sono differenze.

I linguaggi cosiddetti ‘tipizzati’ hanno questo nome proprio perche’ i valori utilizzati nel programma, come variabli ecc., devono avere sempre lo stesso tipo.
E’ questo che permette di compilare il programma e di ottenere un programma piu’ veloce di (ad esempio) un programma Python.

E’ questa la caratteristica di quei linguaggi.
Devi stabilire in anticipo il tipo dei vari valori, e poi ovvaimente rispettare questa decisione nel resto del programma.

Secondo me non ha molto senso cercare di utilizzare questi linguaggi come utilizzi Python. :slight_smile:
In ogni caso provare a farlo mi sembra parecchio complicato …
Direi una cosa da fare solo se e’ proprio necessario.

nell’esecuzione, invece di scegliere l’oggetto, annullo il comando quindi ritorna Cancel altrimenti go

si scusa mi colpa per troppa sintesi, volevo intendere, “richiede” di dare un valore di ritorno di tipo. . .

esatto a questo punto, forse il modo corretto su come formulare la domanda del post sarebbe:

“come fa Python a far accettare ai vari return, oggetti diversi?”

se come dici è una cosa complicata, ovviamente non ne vale la pena, ma era giusto per il piacere di sapere.

Quello si capisce.
La mia domanda (provo a riformulare :smile:) era: come utilizzi il valore resituito dopo, quando richiami quella funzione ?
Cosa ci fai di un valore che non sai che tipo sia ?

Tu hai postato solo la funzione, non l’intero script.
Nello script, come la usi quella funzione ?
Hai un esempio ?

Python e’ un linguaggio di tipo dinamico, non compilato ma interpretato.
E’ piu’ lento appunto perche’ l’interprete ogni volta deve prima capire di che tipo di valore si tratta, e poi utilizzarlo di conseguenza.
E’ la sua caratteristica.

Dicevo che e’ complicato far fare a C# quello che fa Python.
Perche’ Python questa cosa di verificare prima il tipo e quindi agire di conseguenza lo fa in automatico, e ovviamente ci mette del tempo.
Mentre a C# dovresti farglielo fare tu, cioe’ dovresti scrivere tutta questa logica dentro lo script, utilizzando oggetti di tipo object ogni volta che vuoi poter assegnare valori di tipo diverso allo stesso oggetto.

infatti era quello a cui stavo ragionando per aggirare il problema

mi stai confondendo ahahahah

è semplice, se la selezione non va a buon fine mi ritorna Cancel e finisce tutto
se invece la selezione va a buon fine mi ritorna l’oggetto selezionato, in tal caso
prosegue il codice, essendo che questo metodo veniva chiamato da un’altro metodo

quindi oggetto restituito viene associato ad un’altra variabile per poi essere gestita,
non’è nessun codice particolare o chissà che, ho solo svolto una gestione a blocchi.
(per lo meno questo credo di aver fatto)

ps c’é un doppio controllo ovviamente in entrambi i Metodi

E perche’ finisce tutto ?
Se non sai come viene utilizzato il valore restituito, come fai a sapere che finisce tutto ? :slight_smile:

Come prosegue il codice ?
Tu richiami GetCrvs, OK. Resituisce un valore.
Come fai a utilizzare quel valore ?
Non sai nemmeno se e’ un GetObject o un Result …

Da quanto ho forse forse forse capito finora. :wink:
Tu stai cercando un modo per far fare allo script C# una cosa che non sai a cosa serve …
( Cioe’ restituire o un GetObject o un Result )
O almeno, finora non me lo hai detto cosa c’e’ di tanto utile in un valore che puo’ avere due tipi diversi …
Io non ho visto nessun esempio che richiami quella funzione …

Capirei se restituisse una tuple con due valori: un GetObject e un Result.
A quel punto tu sai che il primo elemento della tuple e’ un GetObject e il secondo un Result.
Quindi puoi controllare il Result:
Se e’ OK, usi il GetObjetc per ricavare l’oggetto.
Se no termini lo script.

Ma che avere un solo valore di un tipo indefinito sia cosi’ utile da dover impazzire per far lavorare C# come se fosse Python … a quest’ora e’ proprio oltre le mie misere capacita’ di comprensione …
:wink: :smile: :smile:

1 Mi Piace
import Rhino as rh

def GetCrv():
    go = rh.Input.Custom.GetObject()
    go.SetCommandPrompt("Sel Crv")
    go.Get()
    if go.CommandResult() != rh.Commands.Result.Success: return go.CommandResult()
    return go.Object(0).Curve()

def Main():
    crv = GetCrv()
    if crv == rh.Commands.Result.Cancel: return print(crv)
    # da qui so che oggetto non'è un Result.Cancel
    # e con oggetto curva ci faccio quel che voglio.
Main()

mi sa che nella tirata d’orecchie mi hai dato la soluzione della tupla giusto. . .
:wink:

edit: ma ora che ricordo, non veniva usata anche una sintassi tipo rc obj oggetto creando una tupla. . .

1 Mi Piace

Se Python controlla solo se il valore e’ Cancel, allora perche’ non usi null al posto di Cancel ?
Cosi’ e’ compatibile col tipo restituito. :slightly_smiling_face:

1 Mi Piace
    Rhino.Input.Custom.GetObject go = new Rhino.Input.Custom.GetObject();
    go.SetCommandPrompt( "Select lines" );
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Curve;
    go.GetMultiple( 2, 2);
    if( go.CommandResult() != Rhino.Commands.Result.Success )
      return go.CommandResult();
    if( go.ObjectCount != 2 )
      return Rhino.Commands.Result.Failure;
 
    LineCurve crv0 = go.Object(0).Geometry() as LineCurve;
    LineCurve crv1 = go.Object(1).Geometry() as LineCurve;
    if( crv0==null || crv1==null )

proprio adesso stavo appunto leggendo questo codice di esempio :sob: :sob:

essì come soluzione credo sia questa la strada da percorrere, provo nella pratica e ti faccio sapere.

:+1:

1 Mi Piace

comunque il Metodo è tipizzato come Rhino.Commands.Result
infatti gli oggetti curve vengono lavorate all’interno del Metodo stesso

nel caso se possibile, provo con entrambi i metodi poi nel caso scelgo quale preferisco.
(anche se assegnazione di tuple a più variabili mi sembra sia una cosa di Py)

alla prossima :+1:

stamani sono riuscito a usare la tupla:

using sy = System;
using rh = Rhino;

(rh.Commands.Result, rh.Input.Custom.GetObject) GetCrvs()
{
    rh.Input.Custom.GetObject go = new rh.Input.Custom.GetObject();

    go.SetCommandPrompt("Select Object");

    go.Get();
    
    if (go.CommandResult() != rh.Commands.Result.Success) return (go.CommandResult(), go);
    
    sy.Console.WriteLine( go.ObjectCount );

    return (go.CommandResult(), go);
}

(rh.Commands.Result, rh.Input.Custom.GetObject) unknown = GetCrvs();

sy.Console.WriteLine( unknown.Item1 );
sy.Console.WriteLine( unknown.Item2 );

poi ho optato per l’altra soluzione auspicata:

rh.Commands.Result Mtd(out object obj_ref)
{
    var go = new rh.Input.Custom.GetObject();

    go.SetCommandPrompt("Sel Crv");
    
    go.Get();
    
    obj_ref = go.Object(0);

    if (go.CommandResult() != rh.Commands.Result.Success) return go.CommandResult();
    
    return go.CommandResult();
}

Main();
void Main()
{
    var rc = Mtd(out object obj);
    
    sy.Console.WriteLine( rc );

    sy.Console.WriteLine(obj);
}

sembra che facciano quello che avevo in mente. . .

quindi nella pratica il Metodo si porta dietro il parametro che ha al suo interno, in questo caso l’oggetto.