Domanda

Considera questo:

public class interface Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

E questo:

public class StubPerson : IPerson
{
    int ID { get { return 0; protected set { } }
    string FirstName { get { return "Test" } set { } }
    string LastName { get { return "User" } set { } }
    string FullName { get { return FirstName + " " + LastName; } }
}

Utilizzo:

IPerson iperson = new Person();

o

IPerson ipersonStub = new StubPerson();

o

IPerson ipersonMock = mocks.CreateMock<IPerson>();

Quindi in effetti dichiariamo contemporaneamente l'interfaccia IPerson e la classe Persona :

public class interface Person : IPerson

Pensi che sarebbe utile avere questo tipo di supporto in .NET / C #?

Modifica

A causa della confusione di massa, penso di dover chiarire lo scopo proposto:

Senza questa funzione dovresti scrivere:

interface IPerson
{
  int ID { get; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get; }
}

oltre a questo:

public class Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

Non sto proponendo alcun cambiamento semantico.

È stato utile?

Soluzione

Ho considerato il lo stesso tipo di cose un po 'di tempo fa , in particolare per l'uso nel caso in cui si disponga di una sola implementazione di produzione di un'interfaccia, ma si desidera prenderla in giro per i test. Al momento finisce per essere un po 'come i file .c / .h di un tempo.

Sospetto, alla fine, che i suoi benefici siano compensati dalla maggiore complessità sia nella lingua che nella successiva lettura del codice. Sarei comunque interessato a vederlo esplorato più a fondo però. Anche allora, ci sono altre cose molto più in alto nel mio elenco di priorità: un supporto migliore per l'immutabilità è al top :)

Altri suggerimenti

Fammi vedere se ho capito cosa stai chiedendo:

Perché non possiamo dichiarare un'interfaccia:

interface IPerson
{
    string Name {get;set;}
    int ID {get;set;}
}

E le classi che implementano tale interfaccia erediteranno le sue proprietà senza doverle dichiarare nuovamente:

class Person : IPerson { } 
//person now has properties Name and ID

Il motivo per cui non puoi farlo è anche se il testo del tuo codice di interfaccia e il tuo codice di classe sono molto simili, significano molto cose diverse. L'interfaccia dice semplicemente che "implementatore avrà una stringa Nome con getter e setter". È la classe che dice "restituisce il campo privato quando viene invocato getter per nome." Anche se si utilizza il collegamento di proprietà automatiche per consentire al compilatore di implementare quella logica, è comunque logica , che appartiene alla classe. Solo perché:

string Name {get;set;}

sembra lo stesso in un'interfaccia e in una classe, non significa nemmeno la stessa cosa da remoto.

Sarebbe molto pericoloso per il compilatore implementare una logica arbitraria per adempiere ai tuoi contratti, invece di lamentarti in fase di compilazione per non averli implementati. Potrebbe introdurre bug molto difficili da rintracciare. Far compilare i compilatori al comportamento predefinito quando non viene definito alcun comportamento è una pessima idea.

Credo che Eiffel faccia qualcosa del genere su .NET, al fine di supportare l'ereditarietà multipla. Una dichiarazione di classe produce automaticamente un'interfaccia corrispondente. Quando si fa riferimento al tipo di classe, il compilatore emette invece principalmente un riferimento al tipo di interfaccia. L'eccezione principale è ovviamente nelle espressioni costruttive.

Beh, penso che le altre risposte ti aiuteranno a capire l'uso dell'interfaccia per astrarre la logica in diverse classi concrete, penso anche che puoi realizzare qualcosa di simile a quello che vuoi usando gli strumenti di refactoring integrati in VS.

Definisci la tua classe ...

public class Person
{
  public int ID { get; protected set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string FullName { get { return FirstName + " " + LastName; } }
}

Quindi fai clic con il tasto destro del mouse, seleziona Refactor - > Estrai interfaccia.

Questo creerà un file separato contenente l'interfaccia per la definizione della classe, quindi potresti modellare l'interfaccia e implementare le classi di conseguenza.

Interfaccia estratta:

interface IPerson
{
    string FirstName { get; set; }
    string FullName { get; }
    int ID { get; }
    string LastName { get; set; }
}

Suppongo che mi stia perdendo il punto: cosa stai realizzando mescolando una classe e un'interfaccia insieme? Quale problema stai risolvendo con questo approccio?

Questa:

IPerson iperson = new Person();

è già legale in C #.

Modifica: Per chiarimenti - il codice sopra è legale dato quanto segue:

interface IPerson { }

class Person : IPerson { }

Vorrei almeno che Visual Studio implementasse le mie proprietà da un'interfaccia come proprietà automatiche se lo richiedessi.

Sfortunatamente questa opzione non lo è e devo occuparmi degli stub di eccezione non implementata

No, perché saresti costretto a esporre tutti i membri pubblici di un'interfaccia. Prova ReSharper e non preoccuparti più di questo.

Resharper può fornire questa funzionalità, ad esempio

  1. Puoi prima scrivere la tua classe Person.
  2. Puoi estrarre la tua interfaccia trascinando i membri verso Interfaccia IPerson.

Di conseguenza puoi avere Visual Studio che genera automaticamente gli stub di implementazione per te.

Aggiorna

Ad ogni modo, esponiamo prima le interfacce, citando il codice che hai fornito nella tua domanda:

public class interface Person : IPerson
{
    int ID { get; protected set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get { return FirstName + " " + LastName; } }
}

Devi capire che un'interfaccia non è una classe astratta. Un'interfaccia è semplicemente un contratto , una sorta di progetto, il che significa che dirà a un oggetto cosa aspettarsi in un altro oggetto senza preoccuparsi davvero di come viene implementato.

Una classe astratta, d'altra parte, può contenere frammenti di funzionalità che possono essere ereditati e sovrascritti.

Nel caso sopra, la tua "interfaccia" non è valido perché:

  • non è possibile dichiarare vincoli di ambito sulle interfacce (pubblico, privato, protetto, interno) poiché si tratta di un dettaglio di implementazione
  • non puoi dichiarare un'implementazione predefinita (ad es. la tua proprietà FullName ) perché, di nuovo, si tratta di un dettaglio dell'implementazione

Mi sembra che quello che vuoi davvero sia una classe astratta, ad esempio

public abstract class BasePerson
{
    public abstract int ID { get; protected set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual string FullName { get { return FirstName + " " + LastName; } } 
}

Sto solo indovinando, ma forse è quello che ti serve davvero.

AGGIORNAMENTO 2

Okay, penso di capire cosa vuoi che accada, quindi quello che vuoi è poter scrivere questo:

public interface IPerson
{
    int ID { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get; }
}

E quindi per la tua implementazione devi solo scrivere questo:

public class Person : IPerson
{
    public int ID { get; protected set; }
    public string FullName { get { return FirstName + " " + LastName; } } 
}

Senza la necessità di specificare le proprietà FirstName e LastName.

Il primo problema che dobbiamo affrontare è il fatto che le interfacce non consentono i delimitatori di accesso nella sua implementazione: ciò che accadrebbe è che le proprietà erediterebbero il delimitatore di accesso predefinito, che è privato.

Il secondo è il fatto che mentre ai nostri occhi stringa FirstName {get; impostato; } in un'interfaccia e stringa pubblica FirstName {get; impostato; } in una classe sono uguali, in realtà non lo sono:

  • in un'interfaccia, la definizione della proprietà indicherà che le firme dei metodi per i metodi getter e / o setter saranno disponibili per tutte le classi che implementano tale interfaccia.
  • in una classe, la definizione della proprietà indicherà al CLR di creare un oggetto anonimo che conterrà il valore di detta proprietà.

Sottile differenza per il programmatore, a parte i mondi per il compilatore.

Infine, quando specifichi che stai implementando un'interfaccia, Visual Studio esegue la magia sintattica che crea automaticamente quei tronconi di proprietà per te.

Penso che un'astrazione migliore per questo sia un tratto o, come ho descritto qui , un ruolo. È come un'interfaccia con codice. Il tuo esempio potrebbe essere codificato in questo modo:

public role RPerson { 
  int ID { get; protected set; } 
  string FirstName { get; set; } 
  string LastName { get; set; } 
  string FullName { get { return FirstName + " " + LastName; } } 
} 

public class Person : RPerson { }

public class StubPerson : RPerson { 
    int ID { get { return 0; protected set { } } 
    string FirstName { get { return "Test" } set { } } 
    string LastName { get { return "User" } set { } } 
    string FullName { get { return FirstName + " " + LastName; } } 
} 

// ...

RPerson rperson = new Person(); 

RPerson rpersonStub = new StubPerson(); 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top