C # derleyicisi COM türlerini nasıl algılar?


168

EDIT: Sonuçları bir blog yazısı olarak yazdım .


C # derleyicisi COM türlerini sihirli bir şekilde tedavi eder. Örneğin, bu ifade normal görünüyor ...

Word.Application app = new Word.Application();

... Applicationbir arayüz olduğunu anlayana kadar . Bir arayüzde bir kurucu mu arıyorsunuz? Yoiks! Bu aslında bir Type.GetTypeFromCLSID()ve başka bir çağrıya çevrilir Activator.CreateInstance.

Ayrıca, C # 4'te, refparametreler için ref olmayan bağımsız değişkenleri kullanabilirsiniz ve derleyici, sonuçları atarak başvuruya geçmek için yalnızca yerel bir değişken ekler:

// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");

(Evet, bir takım argümanlar eksik. İsteğe bağlı parametreler hoş değil mi? :)

Derleyici davranışını araştırmaya çalışıyorum ve ilk bölümü taklit edemiyorum. İkinci kısmı sorunsuz yapabilirim:

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
    void Foo(ref int x);
}

class Test
{
    static void Main()
    {
        Dummy dummy = null;
        dummy.Foo(10);
    }
}

Yazabilmek istiyorum:

Dummy dummy = new Dummy();

rağmen. Açıkçası infaz zamanında patlama olacak, ama sorun değil. Sadece deniyorum.

Derleyici tarafından bağlantılı COM PIA'lar için eklenen diğer özellikler ( CompilerGeneratedve TypeIdentifier) hile yapmıyor gibi görünüyor ... sihirli sos nedir?


11
İsteğe bağlı parametreler hoş değil mi? IMO, Hayır hoş değiller. Microsoft, C # 'e şişirme ekleyerek Office COM arabirimlerindeki kusuru düzeltmeye çalışıyor.
Mehrdad Afshari

18
@Mehrdad: İsteğe bağlı parametreler elbette COM'un ötesinde faydalıdır. Varsayılan değerlere dikkat etmelisiniz, ancak bunlar ile adlandırılmış argümanlar arasında, kullanılabilir bir değişmez tür oluşturmak çok daha kolay.
Jon Skeet

1
Doğru. Özellikle, bazı dinamik ortamlarla birlikte çalışmak için adlandırılmış parametreler pratik olarak gerekli olabilir . Elbette, şüphesiz, kullanışlı bir özelliktir, ancak bu ücretsiz olarak geldiği anlamına gelmez. Basitlik maliyeti (açıkça belirtilen bir tasarım hedefi). Şahsen, C # ekibinin bıraktığı özellikler için şaşırtıcı olduğunu düşünüyorum (aksi takdirde, bir C ++ klonu olabilir). C # ekibi harika ama şirket ortamı siyasetten uzak olamaz. Ben sanırım onun PDC'08 konuşma belirtildiği gibi kendisi bu konuda çok mutlu değildi Anders: "nerede kalmıştık geri almak için on yıl sürdü."
Mehrdad Afshari

7
Takımın karmaşıklığı yakından takip etmesi gerekeceğine katılıyorum. Dinamik şeyler çoğu geliştirici için çok az değer katıyor , ancak bazı geliştiriciler için yüksek değer katıyor .
Jon Skeet

1
Çerçeve geliştiricilerinin birçok yerde kullanımlarını tartışmaya başladığını gördüm. IMO, iyi bir kullanım alanı bulana kadar tam zamanı dynamic... COM dışında neden önemli olduğunu görmek için statik / güçlü yazmaya çok alışkınız.
chakrit

Yanıtlar:


145

Hiçbir şekilde bu konuda uzman değilim, ama son zamanlarda ne istediğimi düşündüm: CoClass öznitelik sınıfı.

[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }

Bir coclass, bir veya daha fazla arabirimin somut uygulamalarını sağlar. COM'da, bu tür somut uygulamalar COM bileşeni geliştirmeyi destekleyen herhangi bir programlama dilinde yazılabilir, örneğin Delphi, C ++, Visual Basic, vb.

Arayüzü "somutlaştırabileceğiniz" (ancak gerçekten somutlaştırdığınız ) Microsoft Speech API hakkında benzer bir soruya verdiğim cevaba bakın .SpVoiceSPVoiceClass

[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }

2
Çok ilginç - daha sonra deneyeceğim. Bağlantılı PIA tiplerinde CoClass yoktur. Belki de bağlantı süreciyle ilgili bir şey
Jon Skeet

64
Eric Lippert ve Jon Skeet de cevap verdiğinde kabul edilen cevabı yazarak harika olduğu için +1;) Hayır, gerçekten, CoClass'tan bahsettiği için +1.
OregonGhost

61

Sen ve Michael arasında neredeyse parçaları bir araya getirdin. Bence böyle çalışıyor. (Kodu yazmadım, bu yüzden biraz yanlış belirtebilirim, ama bu nasıl gittiğinden eminim.)

Eğer:

  • bir arabirim türünde "yenisiniz" ve
  • arayüz tipinin bilinen bir sınıfı vardır ve
  • bu arayüz için "pia yok" özelliğini kullanıyorsunuz

daha sonra kod (IPIAINTERFACE) Aktivatörü olarak oluşturulur.

Eğer:

  • bir arabirim türünde "yenisiniz" ve
  • arayüz tipinin bilinen bir sınıfı vardır ve
  • bu arayüz için "pia yok" özelliğini kullanmıyorsunuz

kod, "yeni COCLASSTYPE ()" dediğiniz gibi oluşturulur.

Jon, bu konu hakkında sorularınız varsa doğrudan beni veya Sam'i rahatsız etmekten çekinmeyin. Bilginize, Sam bu özellik konusunda uzmandır.


36

Tamam, bu sadece Michael'ın cevabına biraz daha fazla et koymak (eğer isterse ekleyebilir, bu durumda bunu kaldıracağım).

Word.Application için orijinal PIA'ya bakıldığında, üç tür vardır (olayları yok saymak):

[ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")]
public interface _Application
{
     ...
}

[ComImport, Guid("..."), CoClass(typeof(ApplicationClass))]
public interface Application : _Application
{
}

[ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."), 
 TypeLibType((short) 2), DefaultMember("Name")]
public class ApplicationClass : _Application, Application
{
}

Eric Lippert'in başka bir cevapta bahsettiği nedenlerin iki arayüzü var . Ve orada, dediğin gibi CoClass- hem sınıfın kendisi hem de Applicationarabirimdeki öznitelik açısından .

Şimdi C # 4'te PIA bağlantısı kullanırsak, bunların bir kısmı sonuçta ortaya çıkan ikili dosyaya gömülür ... ama hepsi değil. Sadece bir tür örnek oluşturan bir uygulama Applicationşu türlerle sonuçlanır:

[ComImport, TypeIdentifier, Guid("..."), CompilerGenerated]
public interface _Application

[ComImport, Guid("..."), CompilerGenerated, TypeIdentifier]
public interface Application : _Application

Hayır ApplicationClass- muhtemelen yürütme sırasında gerçek COM türünden dinamik olarak yükleneceği için .

Bir başka ilginç şey, bağlı sürüm ile bağlı olmayan sürüm arasındaki koddaki farktır. Satırı kodalıyorsanız

Word.Application application = new Word.Application();

içinde başvurulan sürümü o kadar biter:

Application application = new ApplicationClass();

oysa bağlantılı versiyonda

Application application = (Application) 
    Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));

"Gerçek" PIA ihtiyacı gibi görünüyor Yani CoClassniteliği, ama orada çünkü bağlantılı versiyonu yok değil bir CoClassderleyici can aslında başvuru. Dinamik olarak yapması gerekiyor.

Bu bilgileri kullanarak bir COM arayüzü taklit ve derleyici bağlamak için olsun olmadığını görmek ...


27

Michael'ın cevabına biraz onay eklemek için:

Aşağıdaki kod derlenir ve çalışır:

public class Program
{
    public class Foo : IFoo
    {
    }

    [Guid("00000000-0000-0000-0000-000000000000")]
    [CoClass(typeof(Foo))]
    [ComImport]
    public interface IFoo
    {
    }

    static void Main(string[] args)
    {
        IFoo foo = new IFoo();
    }
}

Çalışması için hem ComImportAttributeve hem de ihtiyacınız var GuidAttribute.

Ayrıca fareyi üzerine getirdiğinizde aşağıdaki bilgilere dikkat edin new IFoo(): Intellisense bilgileri uygun şekilde alır: Güzel!


teşekkürler, ben deniyordum ama ComImport özniteliği eksikti , ama ben kaynak kodu i F12 kullanarak çalışıyordu sadece CoClass ve Guid gösterir , neden bu?
Ehsan Sajjad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.