COM Interop: What should I do to make a C# property usable as a VARIANT from VBA

半腔热情 提交于 2019-12-03 13:03:40

Here what I did to go around the issue.

Object properties

public object MyObject {
    get ; set;
}

When using a .Net Object property from VBA, reading the property is no problem and it will be correctly seen as a Variant.
Unfortunately, trying to set the property from VBA will fail.

However, using plain methods will work fine:

private object _MyObject;

public object GetMyObject() {
    return _MyObject;
}

public void SetMyObject(object value) {
    if (value == DbNull.Value)
        value = null;   
    _MyObject = value;
}

The check for DBNull is to get around the problem that VBA' Null is actually marshalled as DBNull to .Net.

DateTime?

Now, to make nullable DateTime? work, we can do something like:

private DateTime? _MyDate;

public object GetMyDate() {
    return _MyDate
}

public void SetMyDate(object value) {
    if (value == null || value == DbNull.Value)
        _MyDate = null;   
    else
        _MyDate = (DateTime?)value;
}

And in VBA, we can hide these get/set in properties (assuming we have an existing instance of our class in myclassinstance):

Public Property Get MyDate() As Variant
    MyDate = myclassinstance.GetMyDate()
End Property

Public Property Set MyDate(value as Variant)
    myclassinstance.SetMyDate value
End Property

A more generic way

This is a bit ugly since our C# class is exposing MyDate as GetMyDate/SetMyDate methods instead of properties.
To implement this in a more generic way so the mechanism is usable for all properties in our class, we can use a Dictionary as a backing store:

[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class MyClass {

    private Dictionary<string,object> backingStore = new Dictionary<string,object>();

    public object GetPropertyValue(string propertyName) {
        if (backingStore.ContainsKey(propertyName))
            return backingStore[propertyName];
        else
            return null
    }

    public void SetPropertyValue(string propertyName, object value) {
        if (value == DBNull.Value) value = null;
        if (backingStore.ContainsKey(propertyName))
            backingStore[propertyName] = value;
        else
            backingStore.Add(propertyName, value);
    }

    [ComVisible(false)]
    public DateTime? MyDate {
        get {
            return GetPropertyValue(@"MyDate") ?? default(DateTime?);
        }
        set {
            SetPropertyValue(@"MyDate", value);
        }            
    }
}

The ComVisible(false) attribute ensures that the properties are not visible from VBA.

And in VBA, we declare the properties:

Public Property Get MyDate() As Variant
    MyDate = myclassinstance.GetPropertyValue("MyDate")
End Property

Public Property Set MyDate(value as Variant)
    myclassinstance.SetPropertyValue "MyDate", value
End Property

Create your own NullableDateTime class with the Nullable features such as HasValue and Value properties and GetValueOrDefault method.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!