2010-04-12 21 views

cevap

0

Düzeltme: Lütfen bu cevabın bir düzenlemede tamamen değiştirilmeden önce verildiğini unutmayın. Bundan dolayı, şimdi sadece orijinal olarak belirtilen soruda mevcut olan şeylere atıfta bulunmaktadır. Tüm "sarkan işaretçiler" için af diliyorum. :-)


Kısa cevap: Yayınladığınız kod ile

, ben IFoo<T> için döküm bir alternatif görmüyorum. Eğer yapmazsanız, derleyici bir uyarı verecektir (makinemde, en azından).

Daha ayrıntılı cevap:

kodunuzu aslında bu şekilde olmak zorunda mı? Daha spesifik olarak, öncelikle söz konusu oyuncuya ihtiyacınız var mı?

var stringFoo = FooFactory.CreateFoo<string>(); 

Sen (bu durumda string) şablonu parametresini sağlamak zorunda herhangi bir yöntem argüman elde edilemez açıkça çünkü:

seni az çok bu gibi fabrika yöntemini çağırmak için gidiyoruz varsayalım (bu durumda aslında hiç yoktur). Açıkçası, fabrika yöntemi bir IFoo<string> döndürecektir. Şimdi

, açıkça çalışma anında türünü belirtmek zorunda olduğundan, sadece de yazabiliriz:

var stringFoo = StringFoo.Create(); 

ve bu nedenle bu gibi o koşulsuz bariz yapar StringFoo içinde bir fabrika yöntemine sahip : Bu if zincir veya FooFactory.CreateFoo<T>switch blok kodunuzu yapmak size kazandıracak IFoo<T> uygulamaları çok diğer bu deseni uygulayarak

public class StringFoo : IFoo<string> 
{ 
    ... 

    public static StringFoo Create() // or alternatively, return an IFoo<string> 
    { 
     return new StringFoo(); 
    } 
} 

Daha kolay, ve döküm gerekliliğinden kurtulun (ki bununla ilgili endişeleriniz var).

Yanlış anlama, bazı durumlarda birden çok nesne türü 'u destekleyen fabrika yöntemlerinin yararlı olduğunun farkındayım; ama sizin durumunuzda göründüğünden daha fazla sorun yaratıyor.


P.S. .: İlginç bazı IoC kapları bir yönünü bulabilir.Genellikle yapılandırılmaları gerekir ve bu, soyut arayüzler için somut türleri (yani uygulama sınıfları) kaydettiğiniz bir süreci kapsar; (örneğin burada Autofac kullanarak):

var builder = new ContainerBuilder(); 
builder.RegisterType<StringFoo>().As<IFoo<string>>(); 

Sonra da geç, soyut bir türünde bir nesne örneğini isteyebilir:

using (var container = builder.Build()) 
{ 
    var stringFoo = container.Resolve<IFoo<string>>(); 
    ... 
} 

Resolve yöntem ilginç bir parçasıdır. Bunu soyut bir tiple sağlayın ve kayıtlı türleri kullanarak, StringFoo türünde somut bir nesne döndürür. Ona bak, eğer senden fazla ses gelmiyorsa! :-)

+0

Downvoter'a: Neden, sorabilir miyim? – stakx

+0

@Merritt, endişelenme. Ne de olsa, hepimiz öğrenmek için burada değil miyiz? Bütün bunları yazmamın bir sakıncası yok, çünkü yazma/açıklamadan da çok kar edebilirim. – stakx

0

kopyası? Yaklaşmanın daha açık bir yolu var.

Düzenleme

Ve evet, kod kokuyor. Herhangi bir tür için açık bir oda bıraktınız, daha sonra tek bir türe geri kısıtlama ve bir çalışma zamanı istisnası oluşturma dışında. Bu durumda neden bir parametre var?

+3

Hayır, değilim. Genel bir arayüz sağlayan ancak sonuçta sadece belirli bir somut tip oluşturan soyut bir fabrikanın kullanışlılığını anlamıyorum. Tanımladığınız, henüz tanımlamamış olduğunuz bir soruna bir çözümdür. Bu sorunun nasıl çözüleceğine dair önyargılı fikir yerine, bu sorunun ne olduğunu söyleyin ve size daha iyi yardımcı olacağız. –

+0

Vakumda teknoloji genellikle bir problemin aranmasında çözüm üretiyor. Bu mekanizma tarafından ele alınan durumları tanımlamadan, değer yargısı alabileceğiniz hiçbir kriteriniz yoktur. Sorunuz bu yaklaşımın * bazı * problemleri için geçerli bir çözüm olup olmadığını belirlemek için daha fazlaydıysa, bu farklıdır. Ben jenerik olmayan bir jenerik fabrika için kullanım görmüyorum ve böyle kullanıldığında çalışma zamanı istisnaları neden görmüyorum. Süpermarkete gitmedikçe başlamayacak bir araba yapmak gibi. –

0

Böyle bir şey deneyebiliriz ...

public static class FooFactory 
{ 
    private static readonly Dictionary<Type, Type> FooTypesLookup; 

    static FooFactory() 
    { 
     FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes() 
          let fooInterface = 
          type.GetInterfaces().FirstOrDefault(
           x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>)) 
          where fooInterface != null 
          let firstTypeArgument = fooInterface.GetGenericArguments().First() 
          select new { Type = type, TypeArgument = firstTypeArgument }) 
      .ToDictionary(x => x.TypeArgument, x => x.Type); 
    } 

    public static IFoo<T> CreateFoo<T>() 
    { 
     var genericArgumentType = typeof(T); 
     Type closedFooType; 
     return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType) 
       ? (IFoo<T>) Activator.CreateInstance(closedFooType) 
       : null; 
    } 
} 

Ya da daha iyisi, favori IoC kapsayıcı (Windsor, yapı haritası, vs) tanıtılması ve orada IFoo uygulamak her türlü kayıt ve Activator.CreateInstance çağrısı yerine gerektiğinde bunları çöz.

+0

Benim amacım Activator.CreateInstance() kullanmamaktı. – Merritt

İlgili konular