SORU
10 Mart 2011, PERŞEMBE


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
10 Mart 2011, PERŞEMBE


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

  1. Bir şekilde sorun genericity veya sınıf/arabirimi devralma kullanarak çözmeye var mı?
  2. Sorun dynamic çağırmaları kullanarak çözebilir (sadece .4.0 ve üzeri NET)?
  3. Performans önemli, yani yansıyan yöntem veya örnekleme çağrımı bir kez, ya da milyonlarca kez iki kez aradı mı olacak?
  4. Teknolojileri Akıllı ama düzgün/anlaşılır bir çözüm için birleştirebilir miyim?
  5. 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();
    }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • CaptainDisillusion

    CaptainDisil

    18 EYLÜL 2007
  • Friday Night Cranks

    Friday Night

    27 Mayıs 2007
  • Matt Steffanina

    Matt Steffan

    1 EYLÜL 2011