2009-05-12 7 views
17

Bir dizi türle kullanılmak üzere tasarlanmış bir sarıcı genel sınıfım var. Bu türler bir yardımcı program tarafından üretilir ve tümü temel bir ClientBase'den türetilir. ClientBase yalnızca bir varsayılan kurucuya sahip olsa da, oluşturulan tüm türlerde varsayılan kurucu vardır, ayrıca bir kurucu parametre olarak bir dize alır. Sarmalayıcı sınıfının yapıcısında, bir dize alan kurucu ile türün bir örneğini başlatırım.Genel parametrenin, belirli parametreleri alan bir kurucuya sahip olması nasıl kısıtlanır?

public class ClientBase 
{ } 

public class GenericProxy<T> 
    where T: ClientBase, new() 
{ 
    T _proxy; 

    public GenericProxy(string configName) 
    { 
     _proxy = new T(configName);  
    } 
} 

tipi T bir dize alan yapıcıya sahip garantisi yoktur çünkü bu kod derleme değil: Burada örnek bir koddur. T türünün bir dizeyi alan bir kurucuya sahip olması zorunluluğunu uygulamak için genel sınıf üzerinde bir kısıtlama tanımlamanın bir yolu var mı? Eğer bu mümkün değilse, bu durumun üstesinden gelmek için iyi alternatifler nelerdir?

cevap

24

Bu mümkün değil.

  • başka belirtin
  • T
  • için bir fabrika olarak görev yapacak bir temsilci belirtin: Ben

    Alternatifler ... Bu işlemek için "static interfaces" görmek istiyorum, ama onlara yakın zamanda beklemeyin arayüz başlatma için T kendisinde özel arayüzler T

  • için bir fabrika olarak hareket (ve T arabirimi uygulayan ve böylece bir kısıtlama eklemek) için

Th e ilk iki gerçekten eşdeğerdir. Temelde böyle bir şey için proxy sınıfını değiştirmek istiyorum: (. Ben daha sonra fazla örneğini oluşturmak istiyorum gidiyoruz varsayalım - Aksi siz de yapıcı içine T'nin bir örneğini geçebilirim)

public class GenericProxy<T> 
    where T: ClientBase, new() 
{ 
    string _configName; 
    T _proxy; 
    Func<string, T> _factory; 

    public GenericProxy(Func<string, T> factory, string configName) 
    { 
     _configName = configName; 
     _factory = factory; 
     RefreshProxy(); 
    } 

    void RefreshProxy() // As an example; suppose we need to do this later too 
    { 
     _proxy = _factory(_configName); 
    } 
} 

1

Jon'un belirttiği gibi, bunun için yerleşik destek yoktur - ancak bir kenara yazarak Expression'u kullanarak kurucuya (yansımadan daha hızlı) yazılan bir temsilci oluşturabilirsiniz. Bunu yapmak için kod MiscUtil (MiscUtil.Linq.Extensions.TypeExt) içinde bulunabilir.

1

Bu yöntem kısıtlayıcı, gerçek soruyu cevaplamak, ancak şeyiyle burada Yansıma kullanarak, çalışma zamanında soruyorsun ne yapabilirim nasıl değildir: tam çalışma örneği dayanır Burada

private T Get<T>(string id) 
    { 
    var constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) }); 
    if (constructor == null) throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y)."); 

    var data = GetData(id); 
    return (T)constructor.Invoke(new object[] { data.x, data.y }); 
    } 
0

@JonSkeet Yanıta: ice cream

:

using System; 
using System.Collections.Generic; 

namespace GenericProxy 
{ 
    class Program 
    { 
     static void Main() 
     { 
      GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream"); 

      Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working 
     } 
    } 

    public class ClientBase 
    { 
     static public ClientBase Factory(string configName) 
     { 
      return new ClientBase(configName); 
     } 

     // default constructor as required by new() constraint 
     public ClientBase() { } 

     // constructor that takes arguments 
     public ClientBase(string configName) { _configName = configName; } 

     // simple method to demonstrate working example 
     public string ConfigName 
     { 
      get { return "ice " + _configName; } 
     } 

     private string _configName; 
    } 

    public class GenericProxy<T> 
     where T : ClientBase, new() 
    { 
     public GenericProxy(Func<string, T> factory, string configName) 
     { 
      Proxy = factory(configName); 
     } 

     public T Proxy { get; private set; } 
    } 
} 

şu çıktıyı görmek için bekliyoruz

İlgili konular