Quantcast
Channel: ClearScript
Viewing all articles
Browse latest Browse all 2297

Commented Unassigned: Cannot Access IReadOnlyCollection via interface Property [91]

$
0
0
I am running into a very strange issue where I cannot use the indexer of an IReadOnlyCollection when it is exposed via an interface property. Below is a code example of the problem. The second line of the script results in TypeError: Cannot read property 'SystemName' of undefined. E.g. the indexer is returning undefined. It seems like the indexer should work regardless of if I am accessing the host object directly or via an interface.

>
public interface IDataObject
{
Guid Id { get; set; }

string SystemName { get; set; }

string DisplayName { get; set; }

string Description { get; set; }

IReadOnlyCollection<SubDataObject> ChildrenReadOnly { get; }
}

public class DataObject : IDataObject
{
public DataObject()
{
Children = new List<SubDataObject>();
}

public Guid Id { get; set; }

public string SystemName { get; set; }

public string DisplayName { get; set; }

public string Description { get; set; }

public IReadOnlyCollection<SubDataObject> ChildrenReadOnly { get { return Children; } }

public Char CharTest { get; set; }

public int IntTest { get; set; }

public decimal DecimalTest { get; set; }

public byte ByteTest { get; set; }

public bool? BoolTest { get; set; }

public List<SubDataObject> Children { get; set; }

public string IntTestToString()
{
return IntTest.ToString();
}

public Func<string> DoSomething { get; set; }
}

public class SubDataObject
{
public DataObject Parent { get; set; }

public Guid Id { get; set; }

public string SystemName { get; set; }

public string DisplayName { get; set; }

public string Description { get; set; }
}

private static void ReproduceIReadOnlyCollectionIssue()
{
var dataObj = new DataObject
{
Id = Guid.NewGuid(),
SystemName = "Root Object System Name",
DisplayName = "Root Object Display Name",
Description = "Root Description",
};

dataObj.Children = new List<SubDataObject>
{
new SubDataObject
{
Parent = dataObj,
Id = Guid.NewGuid(),
SystemName = "Sub System Name 0",
DisplayName = "Sub Display Name 0",
Description = "Sub Description 0"
}
};

using (var engine = new V8ScriptEngine())
{
engine.AddHostType("Console", typeof(Console));
engine.AddHostObject("dataObj", dataObj);
engine.AddHostObject("readOnlyCollection", dataObj.ChildrenReadOnly);

const string script = @"
Console.WriteLine(readOnlyCollection[0].SystemName); //works fine
Console.WriteLine(dataObj.ChildrenReadOnly[0].SystemName); //indexer returns undefined.
";
engine.Execute(script);
}
}



Comments: Hello! This behavior is by design. Consider this line from your sample: ``` C# engine.AddHostObject("dataObj", dataObj); ``` With this setup, the expression `dataObj.ChildrenReadOnly` is of type `IReadOnlyCollection<SubDataObject>`. This type doesn't have an indexer, so applying indexing syntax to the result yields `undefined` in JavaScript and a compilation error in C#. To understand why it works in the other case, consider this line: ``` C# engine.AddHostObject("readOnlyCollection", dataObj.ChildrenReadOnly); ``` When you use `AddHostObject()`, you expose the given object's _runtime_ type, which in this case is `List<SubDataObject>` — a type that does have an indexer. Therefore `readOnlyCollection[0]` works as you expect. You may be wondering why ClearScript doesn't always expose the runtime types of managed objects. The reason has to do with C#-style method binding, which relies heavily on static typing. Most script languages don't support static typing, so ClearScript simulates it with a feature called type restriction. Type restriction is the default behavior in ClearScript, although `AddHostObject()` predates it and retains its original behavior for compatibility. A newer method, `AddRestrictedHostObject()`, serves a similar purpose but supports type restriction. In any case, you can use `ScriptMemberAttribute` to disable type restriction for an individual class member, or `ScriptEngine.DisableTypeRestriction` to turn it off globally. Keep in mind however that doing so may break certain method binding scenarios. Good luck!

Viewing all articles
Browse latest Browse all 2297

Latest Images

Trending Articles





Latest Images