C# Aktivatör Kullanılması.Createınstance
Dün bir soru dinamik olarak arama yöntemleri için ya yansıma ya da Strateji Desen kullanarak ilgili sordum.
Ancak, o zamandan bu yana ortak bir arabirim uygulayan tek tek sınıflara yöntemlerini değiştirmeye karar verdim. Nedeni, her sınıfın, bazı benzerlikler de bazı yöntemler bu sınıf için benzersiz gerçekleştirmek taşıyan iken.
Gibi bir strateji kullanarak olmuştu:
switch (method)
{
case "Pivot":
return new Pivot(originalData);
case "GroupBy":
return new GroupBy(originalData);
case "Standard deviation":
return new StandardDeviation(originalData);
case "% phospho PRAS Protein":
return new PhosphoPRASPercentage(originalData);
case "AveragePPPperTreatment":
return new AveragePPPperTreatment(originalData);
case "AvgPPPNControl":
return new AvgPPPNControl(originalData);
case "PercentageInhibition":
return new PercentageInhibition(originalData);
default:
throw new Exception("ERROR: Method " method " does not exist.");
}
Ancak potansiyel sınıfları sayısı arttıkça, yenilerini ekleyerek, böylece kural değişikliği için kapalı kırma tutmak gerekir.
Bunun yerine, gibi bir çözüm kullandım:
var test = Activator.CreateInstance(null, "MBDDXDataViews." _class);
ICalculation instance = (ICalculation)test.Unwrap();
return instance;
Etkili, _class parametre sınıfı çalışma zamanında geçirilen adıdır. Bu ortak bir şekilde bunu yapmak için, bu konuda herhangi bir performans sorunları olacaktır.
Yansıma için oldukça yeni değilim, tavsiyelerinize açığız.
CEVAP
Yansıma kullanırken aşırı zor korumak için karmaşık bir çözüm: bir içinde sonunda olabilir, çünkü kendinize birkaç soru sormak gerekir
- Bir şekilde sorun genericity veya sınıf/arabirimi devralma kullanarak çözmeye var mı?
- Sorun
dynamic
çağırmaları kullanarak çözebilir (sadece .4.0 ve üzeri NET)? - Performans önemli, yani yansıyan yöntem veya örnekleme çağrımı bir kez, ya da milyonlarca kez iki kez aradı mı olacak?
- Teknolojileri Akıllı ama düzgün/anlaşılır bir çözüm için birleştirebilir miyim?
- Derleme zamanı tür güvenlik kaybetmekle karşı mıyım?
Genericity / dinamik
Türlerini bilmiyorum sanırım senin açıklama derleme zamanında, sadece arayüzü ICalculation
paylaşıyorlar. Eğer bu doğruysa, o zaman Sayı (1) ve (2) yukarıda muhtemel senaryo mümkün değildir.
Performans
Bu sormak için önemli bir sorudur. Yansıma 400 kat daha fazla bir ceza engelleyebilir kullanma yükü: çağrıları bile ılımlı bir miktar yavaşlatır.
Çözünürlüğü nispeten kolay: yerine Activator.CreateInstance
kullanın bir fabrika yöntemi (zaten var), bak MethodInfo
oluşturmak bir temsilci, önbellek ve kullanımı temsilci. Bu sadece bir ceza verir ilk çağırma, sonraki çağırmaları yakın yerli performansa sahip.
Teknolojilerini bir araya getirir
Burada çok mümkün, ama gerçekten bu yönde yardımcı olmak için durumunuz hakkında daha fazla bilmek istiyorum. Genellikle, jenerik, önbelleğe alınan yansıma ile birlikte dynamic
bir araya gelerek bir son. Bilgi gizleme OOP normal olarak kullanırken, hızlı, istikrarlı ve genişletilebilir hala bir çözüm ile sona erebilir.
Derleme zamanı tür güvenlik kaybediyor
Beş soru, bu belki de endişelenecek en önemli olanıdır. Çok önemli yansıma hataları hakkında net bir bilgi vermek kendi özel durumlar oluşturmak için. Bunun anlamı: yöntem, yapıcı veya bir özellik bir giriş dizesi dayalı bir arama veya bilgi bir deneyin sarılmış olmalı aksi takdirde kontrolsüz/her yakalamak. Sadece belirli özel durumlar (her zamanki gibi yani: asla Exception
kendisi) yakala.
TargetException
(yöntem yok), 12 ** (yöntem var, ama bir gül odaklanmak. anlamışlardı), TargetParameterCountException
, MethodAccessException
(doğru ayrıcalıkları ASP.NET bir şey oldu bu değil), InvalidOperationException
(genel türler ile olur). Her zaman onları yakalamak için denemek gerek yok, beklenen giriş ve beklenen hedef nesneleri bağlıdır.
Özetle
Senin kurtulmak Activator.CreateInstance
ve Methodınfo fabrikada oluşturma yöntemi bulmak, ve Delegate.CreateDelegate
oluşturun ve temsilci önbellek kullanın. Sadece örnek kodunuzda sınıf-dize eşit olduğu Dictionary
statik içinde saklayın. Aşağıda hızlı değil ama-kirli yani bu güvenli bir şekilde yapıyor ve çok fazla türü kaybetmeden bir güvenlik.
Örnek kod
public class TestDynamicFactory
{
// static storage
private static Dictionary<string, Func<ICalculate>> InstanceCreateCache = new Dictionary<string, Func<ICalculate>>();
// how to invoke it
static int Main()
{
// invoke it, this is lightning fast and the first-time cache will be arranged
// also, no need to give the full method anymore, just the classname, as we
// use an interface for the rest. Almost full type safety!
ICalculate instanceOfCalculator = this.CreateCachableICalculate("RandomNumber");
int result = instanceOfCalculator.ExecuteCalculation();
}
// searches for the class, initiates it (calls factory method) and returns the instance
// TODO: add a lot of error handling!
ICalculate CreateCachableICalculate(string className)
{
if(!InstanceCreateCache.ContainsKey(className))
{
// get the type (several ways exist, this is an eays one)
Type type = TypeDelegator.GetType("TestDynamicFactory." className);
// NOTE: this can be tempting, but do NOT use the following, because you cannot
// create a delegate from a ctor and will loose many performance benefits
//ConstructorInfo constructorInfo = type.GetConstructor(Type.EmptyTypes);
// works with public instance/static methods
MethodInfo mi = type.GetMethod("Create");
// the "magic", turn it into a delegate
var createInstanceDelegate = (Func<ICalculate>) Delegate.CreateDelegate(typeof (Func<ICalculate>), mi);
// store for future reference
InstanceCreateCache.Add(className, createInstanceDelegate);
}
return InstanceCreateCache[className].Invoke();
}
}
// example of your ICalculate interface
public interface ICalculate
{
void Initialize();
int ExecuteCalculation();
}
// example of an ICalculate class
public class RandomNumber : ICalculate
{
private static Random _random;
public static RandomNumber Create()
{
var random = new RandomNumber();
random.Initialize();
return random;
}
public void Initialize()
{
_random = new Random(DateTime.Now.Millisecond);
}
public int ExecuteCalculation()
{
return _random.Next();
}
}
Aktivatör amacı.Örnek createınstance?...
Nasıl harekete geçirmek için Parametre...