2010-10-12 33 views
31

Forse sono sovraccarico, ma non si sta compilando (CS0411). Perché?Gli argomenti tipo per metodo non possono essere dedotti dall'utilizzo

interface ISignatur<T> 
{ 
    Type Type { get; } 
} 

interface IAccess<S, T> where S : ISignatur<T> 
{ 
    S Signature { get; }  
    T Value { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public Type Type 
    { 
     get { return typeof(bool); } 
    } 
} 

class ServiceGate 
{ 
    public IAccess<S, T> Get<S, T>(S sig) where S : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

static class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     var access = service.Get(new Signatur()); // CS4011 error 
    } 
} 

Qualcuno un'idea perché no? O come risolvere?

+1

magari aggiungendo l'errore che si ottiene ... – vulkanino

+1

risposta di Eric Lippert qui, insieme al suo post sul blog a cui si collega, è una buona spiegazione del perché. Fondamentalmente, se ricordo correttamente, il compilatore non dedurrà i tipi usando i vincoli generici.http://stackoverflow.com/questions/3630153/generic-extension-method-type-argument-cannot-be-inferred-from-the-usage/3630202#3630202 –

risposta

42

Get<S, T> accetta due tipi di argomenti. Quando chiami service.Get(new Signatur()); come fa il compilatore a sapere che cos'è T? Dovrai passarlo esplicitamente o cambiare qualcos'altro sulle tue gerarchie di tipi. Passando in modo esplicito sarebbe simile:

service.Get<Signatur, bool>(new Signatur()); 
+0

Sì, volevo evitare la chiamata esplicita. Ma se, come dalla spiegazione di Eric Lippert, i vincoli generici non sono usati per risolvere i tipi generici di ritorno, allora questo non funzionerebbe. Grazie! – Ben

8

Kirk's answer è proprio su. Di norma, non si avrà alcuna fortuna con l'inferenza di tipo quando la firma del metodo ha un numero inferiore di tipi di parametri rispetto a parametri di tipo generico.

Nel tuo caso particolare, sembra si potrebbe possibilmente spostare il parametro T tipo a livello di classe e quindi ottenere l'inferenza di tipo sul tuo Get metodo:

class ServiceGate<T> 
{ 
    public IAccess<S, T> Get<S>(S sig) where S : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

Quindi il codice che avete inviato con il CS0411 errore potrebbe essere riscritto come:

static void Main() 
{ 
    // Notice: a bit more cumbersome to write here... 
    ServiceGate<SomeType> service = new ServiceGate<SomeType>(); 

    // ...but at least you get type inference here. 
    IAccess<Signatur, SomeType> access = service.Get(new Signatur()); 
} 
0

come ho detto nel mio commento, penso che la ragione per cui questo non funziona è perché il compilatore non può dedurre i tipi o base n vincoli generici.

Di seguito è riportata un'implementazione alternativa che verrà compilata. Ho rivisto l'interfaccia IAccess per avere solo il parametro di tipo generico T.

interface ISignatur<T> 
{ 
    Type Type { get; } 
} 

interface IAccess<T> 
{ 
    ISignatur<T> Signature { get; } 
    T Value { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public Type Type 
    { 
     get { return typeof(bool); } 
    } 
} 

class ServiceGate 
{ 
    public IAccess<T> Get<T>(ISignatur<T> sig) 
    { 
     throw new NotImplementedException(); 
    } 
} 

static class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     var access = service.Get(new Signatur()); 
    } 
} 
2

Ora il mio obiettivo era quello di avere una coppia con un tipo di base e una definizione di tipo (Requisito A). Per la definizione del tipo voglio utilizzare l'ereditarietà (Requisito B). L'uso dovrebbe essere possibile, senza conoscenze esplicite sul tipo di base (Requisito C).

Dopo ora so che i vincoli gernic non vengono utilizzati per risolvere il tipo di ritorno generica, ho sperimentato un po ':

introducte

Ok li ha lasciati Get2:

class ServiceGate 
{ 
    public IAccess<C, T> Get1<C, T>(C control) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 

    public IAccess<ISignatur<T>, T> Get2<T>(ISignatur<T> control) 
    { 
     throw new NotImplementedException(); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
    } 
} 

fine, ma questa soluzione raggiunge non requriement B.

successivo tentativo:

class ServiceGate 
{ 
    public IAccess<C, T> Get3<C, T>(C control, ISignatur<T> iControl) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 

} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
     var c = new Signatur(); 
     var bla3 = service.Get3(c, c); // Works!! 
    } 
} 

Bello! Ora il compilatore può inferire i tipi di ritorno generici. Ma non mi piace. Altro tentativo:

class IC<A, B> 
{ 
    public IC(A a, B b) 
    { 
     Value1 = a; 
     Value2 = b; 
    } 

    public A Value1 { get; set; } 

    public B Value2 { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public string Test { get; set; } 

    public IC<Signatur, ISignatur<bool>> Get() 
    { 
     return new IC<Signatur, ISignatur<bool>>(this, this); 
    } 
} 

class ServiceGate 
{ 
    public IAccess<C, T> Get4<C, T>(IC<C, ISignatur<T>> control) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
     var c = new Signatur(); 
     var bla3 = service.Get3(c, c); // Works!! 
     var bla4 = service.Get4((new Signatur()).Get()); // Better... 
    } 
} 

La mia soluzione finale è quella di avere qualcosa di simile ISignature<B, C>, dove B ist il tipo di base e C la definizione ...

Problemi correlati