I have defined a generic class that derives from BindingList and has a nested non-generic class:
class Generic<T> : BindingList<Generic<T>.Inner>
{
public class Inner
{
public object Foo { get; set; }
}
}
A StackOverflowException occurs in mscorlib when attempting to access the Value property via a dynamic reference like so:
dynamic d = new Generic<string>.Inner();
var value = d.Foo; // StackOverflowException
var value = d.Bar // StackOverflowException as well, not a
// 'RuntimeBinderException' like you would expect when
// trying to access a non-existing member
This is the smallest reproduction i was able to make.
Deriving from BindingList is an important detail, if i change it to a List the program executes correctly.
Why does this happen?
Edit:
This is the top of the call stack:
[Managed to Native Transition]
mscorlib.dll!System.RuntimeTypeHandle.Instantiate(System.Type[] inst)
mscorlib.dll!System.RuntimeType.MakeGenericType(System.Type[] instantiation)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.CalculateAssociatedSystemTypeForAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateType aggtype)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.CalculateAssociatedSystemType(Microsoft.CSharp.RuntimeBinder.Semantics.CType src)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.AssociatedSystemType.get()
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.AggregateType atsOuter, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgs)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgsAll)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgsAll)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeCore(Microsoft.CSharp.RuntimeBinder.Semantics.CType type, Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx)
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeArray(Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray taSrc, Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx)
I think the problem is in this place
Generic<T> :BindingList<Generic<T>.Inner>
Notice you use the declared class as a generic parameter in the parent class BindingList. So I believe reflection just ends up with an infinitive loop and you get StackOverflow.
When you use
var d = new Generic<string>.Inner();
compiler just replaces it with Generic.Inner
so it is the same like
Generic<string>.Inner d = new Generic<string>.Inner();
But when you use
dynamic d = new Generic<string>.Inner();
You really use reflection. Again reflection starts digging deeper in your class structure and it goes like... your class => BindingList = > generic parameter of BindingList => your class(because it's a generic parameter of BindingList) = > BindingList = > and so on until you get StackOverflow.
You can change to Generic<T> : BindingList<string> to break this infinitive loop and it works!
Thank you very much for your correction! I investigated this I would say very interesting moment and found that I was right.
First of all, this is not a BUG! This is just how the Microsoft team solved this issue. Again all what I wrote above I believe is true!
So as I said you end up with an infinitive loop and get StackOverflow, but it seems to me that you get it very very fast. So no any long periods when you have no any access to your machine and just it looks like it's dead. I started digging deeper into the structure of BindingList and here the results.
I created
class Example<T> : Level1<Example<T>>
{
public string Name = "111";
}
public class Level1<T>
{
}
and in the main
dynamic d = new Example<string>();
var value = d.Name;
and it works! Then I added another level
public class Level1<T> : Level2<T>
{
}
public class Level2<T>
{
}
and I got StackOverflow. I changed to
public class Level1<T> : Level2
{
}
public class Level2
{
}
and it works again!
So I think that the guys from Microsoft just said ... so this is the max level after no way through and throw the exception.
Now let's look at BindingList<T>
public class BindingList<T> : Collection<T>,
IBindingList, IList, ICollection, IEnumerable, ICancelAddNew,
IRaiseItemChangedEvents
Notice Collection<T>
And look at List<T>
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
Just interfaces....
Therefore it works with List but not with BindingList!My example proves that!I believe they did it intentionally to stop infinitive looping.
Related
I have a double problem here. I need to sort a List<> that I know contains objects of a derived class to the class that the list was declared to contain originally. AND, I need to sort by the return value from a method in that derived class, which takes a parameter. Keep in mind that I already know the List contains objects all of the derived class type.
I've created some sample code here to demonstrate the question since the real code cannot be shared publicly. Note, I have no control over the base conditions here (i.e. the fact that the List<> collection's declared contents are the parent class and that it contains objects of the derived class, which contains a method that takes an argument and returns the values that I need to sort the collection by). So, I doubt I'd be able to use any suggestion that requires changes there. What I think I need is a way to specify (cast?) what is really in the List so I can access the method defined there. But I'm open to other thoughts for sure. Otherwise I'm left with a traditional bubble sort. Thanks.
public class Component
{
public int X;
public int Y;
}
public class ComponentList : List<Component>
{
// Other members that deal with Components, generically
}
public class Fence : Component
{
public int Distance(int FromX, int FromY)
{
int returnValue = 0;
// Caluclate distance...
return returnValue;
}
}
public class Yard : Component
{
// Yada yada yada
}
public class MyCode
{
public List<Component> MyFences;
public MyCode(List<Component> Fences, int FromX, int FromY)
{
// Sort the fences by their distance from specified X,Y
Fences.Sort((A as Fence, B as Fence) => A.Distance(FromX, FromY).CompareTo(B.Distance(FromX, FromY)));
// Or
List<Fence> sortedFences = MyFences.OrderBy(A => A.Distance(FromX, FromY)).ToList();
// Or ???
}
}
Use the Enumerable.Cast<Fence> extension method to transform your IEnumerable<Component> to IEnumerable<Fence>. Then I'd use your second approach (the OrderBy approach) to sort it, but that's my preference.
List<Fence> sortedFences = MyFences.Cast<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
This approach will throw if there is an object in MyFences that can't be cast to Fence. If you expect that the code should only be passed Fences, this might be what you want. If, instead, you want to skip over non-Fence members, you can use:
List<Fence> sortedFences = MyFences.OfType<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
I'm having some problems with encapsulation in C#. There are two specific scenarios that are causing me problems and I believe the issue is related.
Scenario #1
I have a class definition that looks something like this
class MyClass
{
private int _someField;
private OtherClass _otherClass;
public int someField
{
get { return _someField; }
set { _someField = value; }
}
public OtherClass otherClass
{
get { return _otherClass; }
set { _otherClass = value; }
}
}
If I then try and do something like this in a new piece of code
MyClass theClass = new MyClass();
theClass.otherClass.XYZ += 1;
I get told Cannot Modify the return value of 'MyClass.otherClass' because it is not a variable.
Scenario 2#
public partial class trksegType
{
private wptType[] trkptField;
private extensionsType extensionsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("trkpt")]
public wptType[] trkpt
{
get
{
return this.trkptField;
}
set
{
this.trkptField = value;
}
}
}
If I now try and foreach through the wptType array:
foreach (wptType way in trk.trkseg[i])
I get told - foreach statement cannot operate on variables of type 'trksegType' because 'trksegType' does not contain a public definition for 'GetEnumerator'
Even though an array should implicitly allow enumeration.
Can anyone explain what's going on and what I can do to get around this problem, whilst still maintaining best practices.
For scenario 1, I suspect that OtherClass has been defined as a struct. When a struct is accessed from a property accessor a new copy of the struct is created and returned (structs are value types). Changing a property on this new copy will have no effect on the original struct.
The C# compiler detects this and raises that slightly obscure error.
Scenario 1:
The reason is very likely because your OtherClass is a struct and not a class. Value sematics are a bit tricky and mutable value types are considered harmful. So you either want to make OtherClass a class and not a struct or you do something along those lines:
struct OtherClass
{
public int XYZ { get; }
public OtherClass(int xyz)
{
XYZ = xyz;
}
public OtherClass AddToXYZ(int count)
{
return new OtherClass(this.XYZ + count);
}
}
Then you can do
myClass.otherClass = myClass.otherClass.AddToXYZ(1);
Scenario 2:
You either need to implement IEnumerable on trksegType to enumerate over trkpt or actually access trkpt for the enumeration.
In General:
You have violated encapsulation in both scenarios by accessing objects through other objects. Have a look here: http://www.csharp-station.com/Tutorials/lesson19.aspx
You also should consider using better (more explicit) names for your objects. mttng vwls ds nt ncrs rdblty.
(You really shouldn’t post two questions in one.)
Scenario 1
Cannot Modify the return value of 'MyClass.otherClass' because it is not a variable.
This error happens because OtherClass is not a class, but a struct — also called a value type. This means that accessing MyClass.otherClass copies the value instead of returning a reference. You would be modifying this copy, which would be pointless. The compiler catches this because it is always a bug and never useful.
Scenario 2
foreach (wptType way in trk.trkseg[i])
You haven’t told us what trkseg[i] is, but if it is of the type trksegType, then the answer is: because trksegType doesn’t allow any enumeration. It does not implement IEnumerable, IEnumerable<T>, nor does it have a GetEnumerator method of its own.
Perhaps you meant to write:
foreach (wptType way in trk.trkseg[i].trkpt)
because trkpt is an array of wptType. (You might have found this error sooner if you used more meaningful variable names instead of weird combinations of letters that make no sense.)
I can't see anything wrong with your first example - so double check that the sample that errors really does and correct if not.
In the second instance, it looks like you're trying to iterate on an instance of trksegType, rather than the contained trkpt property. Try foreach (wptType way in trk.trkseg[i].trkpt) instead.
I swear I have seen an example of this but have been googling for a bit and can not find it.
I have a class that has a reference to an object and need to have a GET; method for it. My problem is that I do not want anyone to be able to fiddle with it, i.e. I want them to get a read only version of it, (note I need to be able to alter it from within my class).
Thanks
No, there's no way of doing this. For instance, if you return a List<string> (and it's not immutable) then callers will be able to add entries.
The normal way round this is to return an immutable wrapper, e.g. ReadOnlyCollection<T>.
For other mutable types, you may need to clone the value before returning it.
Note that just returning an immutable interface view (e.g. returning IEnumerable<T> instead of List<T>) won't stop a caller from casting back to the mutable type and mutating.
EDIT: Note that apart from anything else, this kind of concern is one of the reasons why immutable types make it easier to reason about code :)
Return a reference to a stripped-down interface:
interface IFoo
string Bar { get; }
class ClassWithGet
public IFoo GetFoo(...);
If the object isn't too complicated/extensive then write an wrapper around it.
for example:
class A {
public string strField = 'string';
public int intField = 10;
}
class AWrapper {
private A _aObj;
public AWrapper(A aobj) {
_aObj = A;
}
public string strField {
get {
return _aObj.strField;
}
}
public int intField {
get {
return _aObj.intField;
}
}
}
So now all you do is give your client code an instance of the AWrapper class so that they may only use what you allow them to see.
this may get a bit complicated and may not scale well if your base class is not set in stone, but for most simple situation it may just do the trick. I think this is called a facade pattern(but don't quote me on that =) )
This isn't possible. Get and set accessors to reference types get and set the reference to the object. You can prevent changes to the reference by using a private (or internal) setter, but you cannot prevent changes to the object itself if it's exposed by a getter.
Your question reads like you're looking for:
public PropertyName { get; private set; }
But then, given the answers so far I'm not sure I'm interpreting your question correctly. Besides, who am I to question Jon Skeet? :)
i agree with ReadOnlyCollection
See my simple code:
private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices
{
get
{
return (_devices.AsReadOnly());
}
}
ReadOnlyCollection dosen't has Add method so user cant add properties to it.BUT ther is no warranty that if user can modify objects by calling their methods....
I have faced this problem in a certain way.
I have a CategoryViewModel class, which have a property Category that I want private read-only :
public CategoryViewModel
{
private Category { get; }
}
In fact, I want it to be exported as read-only to other class. However I can't do such thing.
In my case (maybe it will help some other guys), I want to add it to a repository. The only way that I've found is to have a function with the repository as param 1, and an Action as param 2 :
public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
action(repo, Category);
}
Like that, from elsewhere, I can do such thing :
categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));
This can help other to expose there property only for certains cases and can manage them.
Take this example:
interface IEntity {
string Name { get; set; }
}
class Product : IEntity {
public string Name { get; set; }
public int Count { get; set; } // added member
}
class Client {
void Process() {
var product = new Product();
int count = product.Count; // this is valid
}
}
In the example above, what is the type of product? Is it IEntity or Product? It appears that product is of type concrete implementation (Product). If that is the case, shouldn't var be used only in special circumstances. But I see that tools like resharper recommend using var by default. Shouldn't one program to an interface?
You are not actually "programming to interfaces" if you are still instantiating the concrete class within the method, as the dependency to the concrete Product class still remains. In order to properly program-to-interfaces you must remove the new instantiation, for example by using a factory or IoC.
What if you had a Product like ...
class Product : IFirst, ISecond, IThrid
The only rational thing the complier can do is what it does. I don't limit my use of var, I use it everywhere. I think it makes code far more readable. In this case, I agree with ReSharper across the board.
If you want Product to be of type IEntity, try this:
var product = new Product() as IEntity;
That said, yes you should program to an interface, but in your case you're instantiating the concrete type directly. If you've already created a dependency to the concrete type, just use the concrete type. If not, use a factory or injection to get an instance of the interface. var will work with those rather well. For example:
public class MyExtremelySimpleFactoryExampleClass
{
public IEntity Instantiate()
{
return new Product();
}
}
// elsewhere in your code...
var item = myFactory.Instantiate(); // item is of type IEntity
Finally, no, I don't think var should be used only in "special circumstances". I find it quite useful and use it almost always.
var product = new Product() is of type Product. You could program to the interface if you weren't using members outside that interface (Product.Count isn't on the IEntity interface).
Added:
Also, in VS2008, you can hover over the var keyword in the declaration to see the implied type. This hover/tooltip message also works on the variable name after the declaration line. (from C# In Depth, page 211)
The type that is inferred is the actual type, not any interface or base class that it may implement/inherit.
Consider this:
var answer = "42";
If it would infer an interface rather than the type, the variable type would be something like IComparable instead of string.
The usage of the var keyword relies on it inferring the actual type, or it would not make sense to use it for anything other than anonymous types. As long as the type is obvious you can use it to make the code more readable, but if the type is not completely obvious, you should avoid using it. (My example above is in the gray area, as it does not actually contain the string type name.)
If you use var in this instance, it will be of type Product. I don't like using var by default, as it can make reading code a little confusing at times.
I prefer using var mostly in LINQ queries, but try not to overuse it in other places (like your example). For people using an IDE with intellisense it is fine, but if you are ever reading the code with Notepad (or Notepad++, etc.), you will have a harder time figuring out the type without a little research.
Is it possible to allow methods and properties of the 'this' pointer to be resolved dynamically?
Put another way, can a class have a dynamic superclass?
Clarification
I would like to be able to subclass some class and access properties and methods that aren't defined at compile-time.
class MyClass : DynamicObject
{
public void ReceiveValue(object value) {
MyProperty = value;
}
}
DynamicObject provides a way for my code to get notified that set_MyProperty has been called with the argument value above, correct? I know this is possible if you use a syntax like:
var mc = new MyClass();
...
dynamic dmc = mc;
dmc.MyProperty = value;
But I want to be able to do this from within the methods of MyClass, almost as if I had done:
dynamic dmc = this;
dmc.MyProperty = value;
Does DynamicObject have me covered?
No, you can't have a dynamic base class. Aside from anything else, the system still needs to know how much space to allocate when you create a new instance of your class.
Could you explain what you're trying to achieve? There may well be ways in which dynamic would help without needing quite this behaviour.
EDIT: Okay, having seen your edit - I don't think you can quite do what you want, but if you just use the
dynamic dmc = this;
dmc.MyProperty = value;
or
((dynamic)this).MyProperty = value;
workaround it should be fine. To put it another way: the this reference is always statically typed, but you can have an expression with the value of this but with a dynamic type.
That shouldn't be too onerous unless you're doing a lot of dynamic work - in which case I'd recommend that you use a fully dynamic language instead. If you implement the bulk of your dynamic code in IronPython/IronRuby, you can easily integrate it with your C# code anyway.
This is the basis of polymorphism. The method/property called will be the one given lowest in the heirarchy of the objects type.
How about this:
class B
{
public void M(object o)
{
dynamic i = this;
i.P = o;
}
}
class D : B
{
public object P { get; set; }
}
class Program
{
static void Main()
{
var d = new D();
d.M(1);
}
}
I realize this is a tangent, but there are languages where every class's superclass is dynamic - i.e. where class name resolution is virtual and override-able.