Consider following two data types:
class C
{
public int I { get; set; }
}
struct S
{
public int I { get; set; }
}
Let's try to use them inside the list, for example:
var c_list = new List<C> { new C { I = 1 } };
c_list[0].I++;
var s_list = new List<S> { new S { I = 1 } };
s_list[0].I++; // (a) CS1612 compilation error
As expected, there is compilation error on line (a): CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable. This is fine, because actually we trying to modify temporary copy of S, which is r-value in giving context.
But let's try to do same thing for an array:
var c_arr = new[] { new C { I = 1 } };
c_arr[0].I++;
var s_arr = new[] { new S { I = 1 } };
s_arr[0].I++; // (b)
And.. this works.
But
var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;
will not compile, as expected.
If we look at the produced IL, we will find following:
IL_0057: ldloc.1 // s_arr
IL_0058: ldc.i4.0 // index
IL_0059: ldelema UserQuery.S // manager pointer of element
ldelema loads address of the array element to the top of the evaluation stack. Such behavior is expected with fixed array and unsafe pointers. But for safe context this is a bit unexpected. Why there is a special unobvious case for arrays? Any why there is no option to achieve same behavior for members of other types?
An array access expression is classified as a variable. You can assign to it, pass it by reference etc. An indexer access is classified separately... in the list of classifications (C# 5 spec section 7.1.)
An indexer access. Every indexer access has an associated type, namely the element type of the indexer. Furthermore, an indexer access has an associated instance expression and an associated argument list. When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (ยง7.6.7), and the result of evaluating the argument list becomes the parameter list of the invocation.
Think of this as similar to the difference between a field and a property:
public class Test
{
public int PublicField;
public int PublicProperty { get; set; }
}
...
public void MethodCall(ref int x) { ... }
...
Test test = new Test();
MethodCall(ref test.PublicField); // Fine
MethodCall(ref test.PublicProperty); // Not fine
Fundamentally, an indexer is a pair of methods (or a single one) whereas an array access gives you a storage location.
Note that if you weren't using a mutable struct to start with, you wouldn't see the difference in this way - I'd strongly advise against using mutable structs at all.
A class indexer like the one in List<T> is actually a syntactically convenient way of calling a method.
With arrays however you are actually accesing to the structure in memory. There is no method call in that case.
Related
This question already has an answer here:
Nested object initializer syntax
(1 answer)
Closed 4 years ago.
Whille creating some dummy data for a collection for a WPF/MVVM project, I produced the following wrong code, which compiles fine, but throws an exception at runtime.
There's a nested structure of data objects, which I wrongly instantiate with only the curly braces (looks like writing JavaScript does cause permanent damage to the brain).
using System.Collections.ObjectModel;
namespace testapp
{
class Program
{
static void Main(string[] args)
{
var collection = new ObservableCollection<TopLevelDataObject>();
collection.Add(new TopLevelDataObject{Nested = {Bar = 5}}); // NullReferenceException
}
class TopLevelDataObject
{
public NestedDataObject Nested { get; set; }
public string Foo { get; set; }
}
class NestedDataObject
{
public double Bar { get; set; }
}
}
}
Why does that compile?
If I create an annonymous type, like Nested = new {Bar = 5}, I get the error message during compilation (which thus fails):
Cannot implicitly convert type '<anonymous type: int Bar>' to 'testapp.Program.NestedDataObject'
Why do I not get such an error when ommitting the new operator?
It even gives me a code hint for the property:
My guess would be that {Bar = 5} is simply a code block, which on its own is a valid thing to have.
But why is it valid to assign a code block to anything (in this case, the Nested property)?
Why does that compile?
Because when that code is compiled, it is compiled as just a set of assignment operations. It doesn't all have to be new instances you create.
If you construct a new instance of Nested from the constructor, you can assign a value to Nested.Bar.
Change public NestedDataObject Nested { get; set; } to this to see how it works:
public NestedDataObject Nested { get; } = new NestedDataObject();
(Note you can never assign a value to Nested outside the constructor in the above code!)
Why does that compile?
Because var x = new SomeType{Property = value}; is the same as:
var x = new SomeType();
x.Property = value;
Indeed we can even leave in the () to have var x = new SomeType(){Property = value}; or even var x = new SomeType(argument){Property = value}; combining passing an argument to the constructor and setting a value.
As such you can see that there is always a constructor called, and if you leave out the parentheses that make that explicit its always the nullary (no-argument) constructor.
Meanwhile a type with no explicit constructor always has a public nullary constructor (the "default constructor").
Hence new TopLevelDataObject{Nested = {Bar = 5}} is the same as:
var temp = new TopLevelDataObject();
temp.Nested.Bar = 5; // NRE on temp.Nested
Because TopLevelDataObject could have a constructor that sets `Nestedt then the code you have could work, so it should compile. Of course, because it doesn't have such a constructor it doesn't work.
(Note that initialisers don't operate quite the same with anonymous types, in that case it gets rewritten to call a hidden constructor hence allowing the properties to be read-only even though initialisers cannot be used with read-only properties of non-anonymous types. The syntax allows them to look the same and hence be easily understood as similar but the result is not the same).
I've been struggling to get a cast to work for a class that has a collection of itself. In testing with a root object that has two TypeA elements in the List, when the List does the implicit cast... it enters the conversion code for the TypeA element of the collection, and because this is the top of the tree, returns TypeAIntermediate without entering the foreach loop (that perfect
- there's nothing in SomeAs). But when it returns the converted instance, it appears to start over at the top of the conversion code for the root like nothing happened.
As far as I can tell this never stops. I rewrote this simplified version that follows the same format... hopefully I didn't mess up.
//These are models used in a .Net 4.5 EF6 Library
public class TypeA
{
public string TypeAStuff;
public TypeB JustOneB;
public List<TypeA> SomeAs;
public static implicit operator TypeAIntermediate(TypeA a)
{
//New up an Intermediate A to return.
TypeAIntermediate aI = new TypeAIntermediate();
//And get ready to do handle the collection... a few ways to do this.
List<TypeAIntermediate> children = new List<TypeAIntermediate>();
//...but this appears to create an infinite loop?
foreach (TypeA item in a.SomeAs)
children.Add(item); //Cast from TypeA to to TypeAIntermediate happens here but will just keeps cycling
aI.TypeAStuff = a.TypeAStuff;
aI.JustOneB = a.JustOneB;
aI.SomeAs = children;
return aI;
}
}
public class TypeB
{
public string TypeBStuff;
public static implicit operator TypeBIntermediate(TypeB b)
{
TypeBIntermediate bI = new TypeBIntermediate();
bI.TypeBStuff = b.TypeBStuff;
return bI;
}
}
//These Intermediate Classes live in a .Net35 Library - Unity cannot use Libraries compiled for later .Net Versions.
public class TypeAIntermediate
{
public string TypeAStuff;
public TypeBIntermediate JustOneB;
public List<TypeAIntermediate> SomeAs;
}
public class TypeBIntermediate
{
public string TypeBStuff;
}
Here's how you can write that to avoid stack overflow if you have loops in your hierarchy.
public static implicit operator TypeAIntermediate(TypeA a)
{
return Convert(a, new Dictionary<TypeA, TypeAIntermediate>());
}
private static TypeAIntermediate Convert(
Type A a,
Dictionary<TypeA, TypeAIntermediate> lookup)
{
TypeAIntermediate aI;
if(lookup.TryGetValue(a, out aI))
{
return aI;
}
aI = new TypeAintermediate();
lookup.Add(a, aI);
List<TypeAIntermediate> children = new List<TypeAIntermediate>();
foreach (TypeA item in a.SomeAs)
children.Add(Convert(item, lookup));
aI.TypeAStuff = a.TypeAStuff;
aI.JustOneB = a.JustOneB;
aI.SomeAs = children;
return aI;
}
Basically by using a dictionary you can determine if any TypeA object already has a TypeAIntermediate object created for it in which case you don't need to create it again and just return the corresponding TypeAIntermediate reference. If it hasn't then you create a new TypeAIntermediate and populate it's collection be recursively calling the Create method that also takes the dictionary.
Additionally if you have the same object reference twice in different branches this will only create one TypeAIntermediate reference instead of two.
What's actually going on here:
public decimal[] Coefficients;
public decimal this[int i]
{
get { return Coefficients[i]; }
set { Coefficients[i] = value; }
}
What does the this serve as? Is it some sort of extension to the decimal?
It's an Indexer.
Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that their accessors take parameters.
Example from the linked MSDN:
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer, which will allow client code
// to use [] notation on the class instance itself.
// (See line 2 of code in Main below.)
public T this[int i]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return arr[i];
}
set
{
arr[i] = value;
}
}
}
// This class shows how client code uses the indexer.
class Program
{
static void Main(string[] args)
{
// Declare an instance of the SampleCollection type.
SampleCollection<string> stringCollection = new SampleCollection<string>();
// Use [] notation on the type.
stringCollection[0] = "Hello, World";
System.Console.WriteLine(stringCollection[0]);
}
}
// Output:
// Hello, World.
It is an indexer it will be called when you use syntax like obj[1]. https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
Have you ever wondered how List<T>'s myList[i] works in c# just like an array ?
The Answer is in your question. The syntax you posted is a syntactic sugar that the compiler transforms into properties called get_Item(int index) and set_Item(int index, decimal value). It is used in List<T> for example to access the internal array used in the class and return the element at the specified index (set or get). This feature is called an Indexer.
To test that yourself, try to create a method with same signature :
public decimal get_Item(int i)
{
return 0;
}
You'll get a compiler error :
Error CS0082: Type 'MyClass' already reserves a member called
'get_Item' with the same parameter types
public class MyType
{
public int SomeProperty { get; set; }
}
public class CustomArray
{
public MyType this[int index]
{
//some code
}
}
var intList = new List<int>();
var arr = new CustomArray();
Array.ForEach(arr, x => intList.Add(x.MyProperty));
This will not compile saying:
The type arguments for method void System.Array.ForEach(T[],
Action) cannot be inferred from the usage.
How can that be?
The CustomArray type is not an array, it's a custom type with an indexed property.
The ForEach<T> method expects an array with elements of type T, and it didn't get one.
Just because you can use the same operator ([]) on both and array and an indexed property, does not mean they are the same thing. For example, arrays are sequential by nature, meaning that if a[0] and a[2] exist, that implies the existence of a[1]. Indexed properties, on the other hand, are more like methods that get a parameter, and they are free to do with it whatever they want.
If you want to declare an array of MyType objects, you do not need to do any special declarations, you can just do:
var arr = new MyType[10];
and now you have an array that can house 10 MyType objects. Initially the values in any of the array's slots is null (assuming MyType is a class).
Also I would steer clear of the Array.ForEach method, I'd prefer using a simple for or foreach loop, or maybe, in this particular case, the List.AddRange method:
intList.AddRange(arr.Select(x=> x.MyProperty));
Is it possible to check if the list contains an object of given (but dynamic) type, derrived from same basic abstract class?
The main problem is not about the list, but about comparing types itself.
In single variables and static variables, it's easy:
if(someVariable is int)
Checking the list with static type is also easy, like:
SomeList.OfType<int>().Any()
or
(from _Object in SomeList.OfType<int> where _Object is int select _Object).Count() == 0
but I cant't handle it if the type I want to check is dynamic, f.e. passed as method parameter:
abstract class BasicClass;
class DerivativeOne : BasicClass { }
class DerivativeTwo : BasicClass { }
// in main:
List<BasicClass> _List = new List<BasicClass>();
DerivativeOne a = new DerivativeOne();
DerivativeTwo b = new DerivativeTwo();
DerivativeOne c = new DerivativeOne();
if(!CheckIfTypeExistsInList(a, _List)
{
_List.Add(a);
}
if(!CheckIfTypeExistsInList(b, _List)
{
_List.Add(b);
}
if(!CheckIfTypeExistsInList(c, _List)
{
_List.Add(c); // this is what I don't want to happen,
// because I already have one object of type DerivativeOne in my list.
}
// the function:
bool CheckIfTypeExistsInList(BasicClass pObject, List<BasicClass> pList)
{
/// few attempts:
pList.OfType<(pObject.GetType()>().Any(); // attempt one, error
return (from _Object in SomeList.OfType<(pObject.GetType())> where _Object is int select _Object).Count() == 0; // attempt two, error
}
PS. I am aware that the code doesn't look neat, but I tried to show just the problem itself, skipping extra logic and stuff.
PS2. I am aware that the solution to the problem would be just to put some attribute to BasicClass and make each derivative to have unique value of the attribute, but still - I'm not looking for another route to solve the problem, I'm just interested if it's possible to do it "this" way.
When the type is known only at runtime, you cannot use it in a generic without using reflection. However, your task is simpler than that - you can use type equality to achieve the results that you want:
Type targetType = pObject.GetType();
if (SomeList.Any(o => targetType.Equals(o.GetType()))) {
...
}