Domanda

Ho lavorato con fornitori un bel po' ultimamente e mi sono imbattuto in una situazione interessante in cui volevo avere una classe astratta che avesse un metodo statico astratto.Ho letto alcuni post sull'argomento e in un certo senso aveva senso, ma esiste una spiegazione chiara e chiara?

È stato utile?

Soluzione

I metodi statici no istanziato in quanto tali, sono disponibili solo senza un riferimento all'oggetto.

Una chiamata a un metodo statico viene effettuata tramite il nome della classe, non tramite un riferimento a un oggetto, e il codice Intermediate Language (IL) per chiamarlo chiamerà il metodo astratto tramite il nome della classe che lo ha definito, non necessariamente il nome di la classe che hai utilizzato.

Lasciatemi mostrare un esempio.

Con il seguente codice:

public class A
{
    public static void Test()
    {
    }
}

public class B : A
{
}

Se chiami B.Test, in questo modo:

class Program
{
    static void Main(string[] args)
    {
        B.Test();
    }
}

Quindi il codice effettivo all'interno del metodo Main è il seguente:

.entrypoint
.maxstack 8
L0000: nop 
L0001: call void ConsoleApplication1.A::Test()
L0006: nop 
L0007: ret 

Come puoi vedere, la chiamata viene effettuata ad A.Test, perché è stata la classe A a definirlo, e non a B.Test, anche se puoi scrivere il codice in questo modo.

Se tu avessi tipi di classe, come in Delphi, dove puoi creare una variabile riferita a un tipo e non a un oggetto, avresti più utilizzo per metodi statici virtuali e quindi astratti (e anche costruttori), ma non sono disponibili e quindi le chiamate statiche non lo sono -virtuale in .NET.

Mi rendo conto che i progettisti IL potrebbero consentire la compilazione del codice per chiamare B.Test e risolvere la chiamata in fase di esecuzione, ma non sarebbe comunque virtuale, poiché dovresti comunque scrivere una sorta di nome di classe lì.

I metodi virtuali, e quindi astratti, sono utili solo quando si utilizza una variabile che, in fase di esecuzione, può contenere molti tipi diversi di oggetti e quindi si desidera chiamare il metodo giusto per l'oggetto corrente presente nella variabile.Con i metodi statici è comunque necessario passare attraverso il nome di una classe, quindi il metodo esatto da chiamare è noto in fase di compilazione perché non può e non cambierà.

Pertanto, i metodi statici virtuali/astratti non sono disponibili in .NET.

Altri suggerimenti

I metodi statici non possono essere ereditati o sovrascritti ed è per questo che non possono essere astratti.Poiché i metodi statici sono definiti sul tipo, non sull'istanza, di una classe, devono essere chiamati esplicitamente su quel tipo.Quindi, quando vuoi chiamare un metodo su una classe figlia, devi usare il suo nome per chiamarlo.Ciò rende l'ereditarietà irrilevante.

Supponiamo che potresti, per un momento, ereditare metodi statici.Immagina questo scenario:

public static class Base
{
    public static virtual int GetNumber() { return 5; }
}

public static class Child1 : Base
{
    public static override int GetNumber() { return 1; }
}

public static class Child2 : Base
{
    public static override int GetNumber() { return 2; }
}

Se chiami Base.GetNumber(), quale metodo verrebbe chiamato?Quale valore restituito?È abbastanza facile vedere che senza creare istanze di oggetti, l'ereditarietà è piuttosto difficile.I metodi astratti senza ereditarietà sono semplicemente metodi che non hanno un corpo, quindi non possono essere chiamati.

Un altro intervistato (McDowell) ha affermato che il polimorfismo funziona solo per le istanze di oggetti.Questo dovrebbe essere qualificato;ci sono linguaggi che trattano le classi come istanze di un tipo "Classe" o "Metaclasse".Questi linguaggi supportano il polimorfismo sia per i metodi di istanza che per quelli di classe (statici).

C#, come Java e C++ prima di esso, non è un linguaggio di questo tipo;IL static La parola chiave viene utilizzata esplicitamente per denotare che il metodo è vincolato staticamente anziché dinamico/virtuale.

In aggiunta alle spiegazioni precedenti, le chiamate al metodo statico sono legate a un metodo specifico su fase di compilazione, che esclude piuttosto il comportamento polimorfico.

Ecco una situazione in cui è sicuramente necessaria l'ereditarietà per campi e metodi statici:

abstract class Animal
{
  protected static string[] legs;

  static Animal() {
    legs=new string[0];
  }

  public static void printLegs()
  {
    foreach (string leg in legs) {
      print(leg);
    }
  }
}


class Human: Animal
{
  static Human() {
    legs=new string[] {"left leg", "right leg"};
  }
}


class Dog: Animal
{
  static Dog() {
    legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
  }
}


public static void main() {
  Dog.printLegs();
  Human.printLegs();
}


//what is the output?
//does each subclass get its own copy of the array "legs"?

In realtà sovrascriviamo i metodi statici (in Delphi), è un po' brutto, ma funziona perfettamente per le nostre esigenze.

Lo usiamo in modo che le classi possano avere un elenco dei loro oggetti disponibili senza l'istanza della classe, ad esempio abbiamo un metodo simile a questo:

class function AvailableObjects: string; override;
begin
  Result := 'Object1, Object2';
end; 

È brutto ma necessario, in questo modo possiamo istanziare solo ciò che serve, invece di istanziare tutte le classi solo per cercare gli oggetti disponibili.

Questo era un semplice esempio, ma l'applicazione stessa è un'applicazione client-server che ha tutte le classi disponibili in un solo server e più client diversi che potrebbero non aver bisogno di tutto ciò che ha il server e non avranno mai bisogno di un'istanza dell'oggetto.

Quindi è molto più semplice da mantenere rispetto ad avere un'applicazione server diversa per ciascun client.

Spero che l'esempio sia stato chiaro.

I metodi astratti sono implicitamente virtuali.I metodi astratti richiedono un'istanza, ma i metodi statici non hanno un'istanza.Quindi, puoi avere un metodo statico in una classe astratta, semplicemente non può essere astratto statico (o statico astratto).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top