Reputation: 720
I have 2 codes in vb.net and C# ( I think they are identical ) :
C#
class ChildClass
{ }
class MyClass
{
public ICollection<ChildClass> Children { get; set; }
public MyClass()
{
Children = new HashSet<ChildClass>() { new ChildClass() };
}
}
T e1<T>(T entity)
where T : class, new()
{
T copy = new T();
return copy;
}
void Test()
{
MyClass myClass = new MyClass();
dynamic children = typeof(MyClass).GetProperty("Children").GetValue(myClass);
dynamic child = Enumerable.ElementAt(children, 0);
dynamic copy = e1(child);
}
VB.NET
Public Class ChildClass
End Class
Public Class MyClass
Public Property Children As ICollection(Of ChildClass) = New HashSet(Of ChildClass)
End Class
Public Function e1(Of T As {Class, New})(entity As T) As T
Dim clone As New T()
Return clone
End Function
Sub Main()
Dim someClass = New MyClass
someClass.Children.Add(New ChildClass)
Dim el = Enumerable.ElementAt(CallByName(someClass, "Children", CallType.Get), 0
Dim el3 = CTypeDynamic(el, GetType(ChildClass))
Dim copy = e1(el3)
End Sub
Now the last line of each code ( where the E1 function is used ) is producing a different object type :
in c# ---- the copy has ChildClass type
in vb.net .... the copy has Object type
What should I do in order that the vb.net code to produce a ChildClass type object ?
Thank you !
Upvotes: 1
Views: 345
Reputation: 172468
I know that you have already accepted an answer, but, for completeness, I'd still like to answer your question "How can I do this in VB.NET"?
The reason for the behaviour is that generics are a compile-time feature. At compile-type, the type of el3
is Object
, so T
is resolved as Object
. The same would happen if you declared child
as object
in C#.
Since VB.NET does not have a dedicated late-binding type (Object
serves as both a regular type as well as a late-binding type if Option Strict is Off), you will have to resort to reflection for run-time generics resolution. Basically, you can replace
Dim copy = e1(el3)
with
Dim copy = Me.GetType().GetMethod("e1").MakeGenericMethod(el3.GetType()).Invoke(Me, {el3})
which yields the same result as your C# code.
Side note: This is actually how dynamic dispatch was commonly done in C# before the introduction of the dynamic
keyword.
Upvotes: 0
Reputation: 13217
The problem is that the dynamic
type in C# tries to mimic the behaviour of the value if the compiler knew its type. Therefore, passing it to a method infers the type arguments from its type at run-time. VB.NET doesn't do such things, el3
is of type Object
. One way you can solve it is to remove the generic parameters:
Public Function e1(entity As Object) As Object
Dim clone = Activator.CreateInstance(entity.GetType())
Return clone
End Function
Upvotes: 1