Вызов метода Interface с использованием переменной типа System.Object в VB.NET - PullRequest
0 голосов
/ 06 января 2011

У меня есть интерфейс ITest с методом GetResult().У меня есть класс Test, который реализует ITest и тем самым определяет закрытый метод GetResult ().

Далее я создаю экземпляр Test в другом классе.Код выглядит следующим образом:

Module NewClass
    Public Sub New()
       Dim i As ITest = New Test()

       Dim o As Object
       o = i

       Dim b As Boolean = o.GetResult()  'This line raises "MissingMemberException" Public member 'Certify' on type 'Class1' not found. '
    End Sub 
End Module

Я должен иметь Object o ссылку на это, так как у меня есть другой код, которому нужно следовать, который зависит от o.Пожалуйста, помогите

Редактировать :

Вот код в вызывающем модуле

Интерфейс:

Public Interface ITest
    Function GetResult() As Boolean
End Interface

Class Test
    Implements ITest

    Private Function ITest_GetResult() As Boolean Implements ITest.GetResult
        Dim result As Boolean
        ......
        ......
        Return result
    End Function
End Class

Edit 2 :

Спасибо за мгновенный ответ.

@ Vlad - Я переносу существующий код из VB 6 в VB.NET и, следовательно, не должен изменять доступмодификатор GetResult.Если оставить его Private, то возникнет InvalidCastException. Невозможно привести объект типа 'System.Object' к типу 'ITest'.

@ Dan. Переменная типа объекта o используется во многих местах, и поэтому я не хочу ее менять.,И да, Test реализует ITest.GetMember с другим именем.

Ответы [ 4 ]

3 голосов
/ 06 января 2011

Мне нужно, чтобы Object o ссылался на это, поскольку у меня есть другой код, которому нужно следовать, который зависит от o.

Что вы имеете в виду?Знаете ли вы, что где бы у вас ни был код, ожидающий Object, он может принять ITest?Это одно из больших преимуществ наследования.

Что касается MissingMemberException: не могли бы вы дать определения для ITest, Test и Class1?Если тип Test реализует ITest.GetMember, используя метод с другим именем (это допустимо в VB.NET), это может объяснить исключение, хотя, похоже, именно в этом и заключается проблема.Просмотр соответствующего кода из ваших классов Test и Class1, в частности, должен помочь.


Редактировать : В зависимости от вашего обновления, вот что происходит.Вы смешиваете позднюю привязку в VB.NET с концепцией .NET интерфейсов .Оба поддерживаются в VB.NET, но это не одно и то же.

Поэтому, когда у вас есть Object, вы можете вызывать любой метод.Это будет решено во время выполнения.Но это должен быть метод, который на самом деле относится к типу объекта .В случае Test функция GetMember отсутствует;есть только функция ITest_GetMember.Поэтому, чтобы использовать позднюю привязку, вам нужно было бы вызвать o.ITest_GetMember (и этот метод также должен быть общедоступным, я считаю).

Тем не менее, Я настоятельно советуюпротив смешивания реализации интерфейса и позднего связывания таким образом .На самом деле, я бы рекомендовал против позднего связывания вообще в случаях, подобных этому, когда у вас действительно есть интерфейс.Я действительно не вижу веской причины для того, чтобы приводить вашу строго типизированную переменную ITest к переменной типа Object;как я уже говорил ранее, вы можете всегда использовать ITest в качестве Object (Object - это root иерархии типов .NET; вы можете использовать что-нибудь как Object), но то, что вы не можете всегда делать, это использовать Object как что-то еще.

Похоже, вы жертвуете удобством использованияваша i переменная (в приведенном вами примере кода) без уважительной причины.


Edit 2 : если подумать, вы передаете Object ссылки ByRef?Если это так, я полагаю, что это может быть законной причиной (хотя я скептически отношусь к тому, что у вас будут веские причины для этого).

Если это так, вам просто нужно разыграть свой Object вернуться к ITest, чтобы использовать членов ITest.(Видите, поскольку у вас уже есть и ITest переменная в i, именно поэтому я продолжаю задавать вопрос о вашем повышении до Object.)

2 голосов
/ 06 января 2011

Я давно не работаю с VB.NET, но вы можете попробовать:

Сделать метод GetResult () в качестве друга или публичного

Если это не работаетзатем попытайтесь привести ваш объект o к интерфейсу ITest

(DirectCast(o, ITest)).GetResult()

Но вы все равно должны иметь свой метод, реализующий интерфейс как друга или общедоступного.

1 голос
/ 06 мая 2013

На самом деле вы можете вызывать интерфейс, не вводя его повторно, если у вас не установлен параметр Option Strict, но вы получите ошибку, которую вы получите, если для параметра strict установлено значение on.

Но опять же, как правильно это сделать, если для параметра Option Strict установлено значение on?

EDIT Я получил ответ, который относится к моему сценарию и, в большей степени, к вопросу выше. Единственное отличие от моего сценария заключается в том, что интерфейс реализован в спутниковом классе (и, следовательно, загружен как сборка). Итак, вот решение кода, которое применимо к вопросу выше, ЕСЛИ интерфейс реализован в сборке, которая загружается во время выполнения.

For Each x In AppDomain.CurrentDomain.GetAssemblies()
    Dim myType = (From t In x.GetTypes() Where t.IsClass And t.GetInterface("ITest") IsNot Nothing Select t).FirstOrDefault
    'you can add other criteria inside the linq expression above to match, e.g the assembly version and / or the assembly string (which contains assembly's version)
    If myType IsNot Nothing Then
        Dim obj = Assembly.GetAssembly(myType).CreateInstance(myType.FullName)
        Dim result As Boolean = CType(myType.InvokeMember("ITest_GetResult", BindingFlags.Default Or BindingFlags.InvokeMethod, Nothing, obj, Nothing), Boolean)
    End If
Next
0 голосов
/ 29 апреля 2014

Это побочный эффект «бокса и распаковки» (или отсутствия распаковки).Я не могу вспомнить какой-либо конкретный ресурс, который я бы порекомендовал, но я бы прочитал несколько блогов, в которых подробно рассказывается о сантехнике, приводящем вещи к типу Object и обратно.По сути, поскольку вы используете позднюю привязку, VB ide / compiler преобразует ваш код в код, который использует отражение против типа этого экземпляра, то есть Test.Для уточнения обратитесь к приведенному ниже коду:

Dim o As Object
o = i '<-- right here is "boxing". its "boxed" up and can be treated 
''as an "Object" object. This allows it to be treated [covariantly][1]

'' What you typed: 
Dim b As Boolean = o.GetResult() '<--right here it needs to be unboxed 
''in order for the compiler to map the interface implementation. What 
''happens instead is shown below.

'' What compiled: (after converted back to vb code from IL)
'' .....keep in mind, o.GetType() returns the same type as 
''GetType(Test), NOT GetType(ITest)
Dim b As Boolean = o.GetType().InvokeMember("GetResult", 
     BidingFlags.Instance or BidningFlags.InvokeMethod 
     Or BindingFlags, Nothing, o, New Object() {})

Теперь код на самом деле, вероятно, немного отличается, я просто аппроксимирую его, чтобы продемонстрировать, что происходит.Вызов такого члена из объекта Type только ищет и выполняет объявленные члены экземпляра.Среда выполнения не выполняет поиск и не пытается сопоставить реализации интерфейса (из-за производительности, безопасности и ряда других причин).Я не уверен, есть ли у вас какие-либо ограничения на это, но вам действительно нужно изменить весь этот код, который использует ту же самую переменную.Каждый вызов метода и свойство get / set направляется через отражение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...