C# array of different objects - c#

I have 2 classes B and D. I have to create an array with 4 elements 2 of type B and 2 of type D. How do I do it?
B o1 = new B();
D o2 = new D();
B o3 = new B();
D o4 = new D();
The array should be something like this:
array[0] = o1; array[1] = o2; array[2] = o3; array[3] = o4;

If there is no common base class other than object, you just need:
object[] array = new object[4];
array[0] = o1;
// etc
Or in a single shot:
object[] array = { o1, o2, o3, o4 };
To use the members specific to B or D, you'd need to cast when you retrieved the values from the array, e.g.
B b = (B) array[0];
b.SomeMethodDeclaredOnB();
If B and D have common methods, you could declare those in an interface which both classes implemented, and change the type of the array:
IBD[] array = new IBD[4];
array[0] = o1;
...
array[0].SomeMethodDeclaredInIBD();
Or:
IBD[] array = { o1, o2, o3, o4 };
...
array[0].SomeMethodDeclaredInIBD();
Finally, to address this:
I am new to c#. I don't like it but I have to learn it. In PHP it's 10000 times easier;
I'm sure if I tried to use PHP I'd find the same experience in the exact opposite direction. Don't assume that C# is "worse" or "harder" than PHP - it's just different, and you're bound to find it harder to use a language you're not familiar with than your "comfort zone" language.

or use array object[] array of objects
or more OOP approch:
public class B : IHolder {
}
public class D : IHolder {
}
IHolder[] arrays of IHolders

I am new to c#. I don't like it but I have to learn it. In PHP it's 10000 times easier;
You left out a part of the last sentence: "to make mistakes". Strong-typedness has its strengths.
You can let the classes B and D inherit from a common base class or interface like such:
interface ISomeInterface
{
string CommonProperty { get; }
}
class B : ISomeInterface
{
public string CommonProperty { get; }
}
class D : ISomeInterface
{
public string CommonProperty { get; }
}
ISomeInterface[] array = new ISomeInterface[]
{
o1,
o2,
o3,
o4
}

Related

can't use type stored in a type array

I have a base class called a, and it has a virtual function called Foo
class a
{
public virtual void Foo() {}
}
And i have a bunch of other classes inheriting from it.
class B : A{}
class C : A{}
class D : A{}
class E : A{}
Now, i want to have an array of the types so i can choose one by random so i tried this:
class Boo
{
Type[] options;
public Boo()
{
options = new[]
{
typeof(B),
typeof(C),
typeof(D),
typeof(E)
};
}
}
And then i want to choose one at random and use its Foo method and i did it like this:
Random rnd = new Random();
(options[rnd.Next(options.Length)] as A).Foo()
But this doesn't work, is there any way of accomplishing this?
(Btw, i didn't have a good name for this so if anyone has a better name they can feel free to edit :) )
options should be an array of A-instances, not a Type[].
class Boo {
public A[] options;
public Boo() {
options = new[] {
new B(),
new C(),
new D(),
new E()
};
}
}
C# fiddle
You cannot do that because your options array holds the types themselves, not instances.
You can do something like
Random rnd = new Random();
var type = options[rnd.Next(options.Length)]
var instance = Activator.CreateInstance(type) as A;
instance.Foo();
If you want to invoke Foo you have to create an instance first, then invoke:
((options[rnd.Next(options.Length)].GetConstructor(new Type[0]).Invoke(null)) as A).Foo()
Other answers have already described how to fix your original code.
However, as an alternative, you could just use a switch statement or similar approach:
public static A RandomlyCreateA(Random rng)
{
switch (rng.Next(4))
{
case 0: return new B();
case 1: return new C();
case 2: return new D();
case 3: return new E();
default: throw new InvalidOperationException("Can't happen!");
}
}
Or if you want to use reflection to choose randomly from all types that inherit from class A (that are defined in the same assembly as class A):
public static A RandomlyCreateA(Random rng)
{
var types = Assembly.GetAssembly(typeof(A)).GetTypes().Where(t => t.IsSubclassOf(typeof(A))).ToArray();
return Activator.CreateInstance(types[rng.Next(types.Length)]) as A;
}

Possible to pass type object to constructor that accepts an unknown var type in C#?

I have been looking for a way to pass an object as unknown type in c# without casting the object?
Essentially I am using reflection to grab the constructor parameters of a class, and I have variables that are casted as objects that I need to pass to the constructor, except I have found no way to dynamically cast the vars...
Code Sample:
public class bClass {
public bClass(string c) {
d = c;
}
}
object a = "asdfasdf";
bClass b = new bClass(a);
I have been able to get the type of variable bClass accepts in the constructor using
var obj = typeof(bClass).GetConstructors();
foreach(var nObj in obj) {
foreach(var param in nObj) {
string sAObjectType = param.ParameterType;
}
}
however, I am not sure how to cast 'a' to type sAObjectType, any ideas are greatly appreciated =]
Thank you!
What about using generics - then you don't have to worry to much about conversion etc.
public class bClass<T>
{
privat T d;
public bClass(T c)
{
d = c
}
}
Then things like below will work.
bClass b1 = new bClass( "1234" );
bClass b2 = new bClass( 12 );
...

What's the equivalent of C# IEnumerable in Java? The covariant-capable one, not the Iterable

This covariance is possible in C#:
IEnumerable<A> a = new List<A>();
IEnumerable<B> b = new List<B>();
a = b;
...
class A {
}
class B : A {
}
This is not possible in Java: (Iterable: Seen in this question Java Arrays & Generics : Java Equivalent to C# IEnumerable<T>).
Iterable<A> a = new ArrayList<A>();
Iterable<B> b = new ArrayList<B>();
a = b;
...
class A {
}
class B extends A {
}
With Iterable, Java doesn't see those two collection are covariance
Which iterable/enumerable interface in Java that can facilitate covariance?
Another good example of covariance, given the same A class and B class above, this is allowed on both Java and C# :
A[] x;
B[] y = new B[10];
x = y;
That capability is on both languages from their version 1. It's nice that they are making progress to make this a reality on generics. C# has lesser friction though in terms of syntax.
Covariance is a must on all OOP languages, otherwise OOP inheritance will be a useless exercise, e.g.
A x;
B y = new B();
x = y;
And that power should extend to generics as well.
Thanks everyone for the answer and insights. Got now a reusable method with covariant-capable Java generics now. It's not the syntax that some of us wants, but it(<? extends classHere>) certainly fits the bill:
import java.util.*;
public class Covariance2 {
public static void testList(Iterable<? extends A> men) {
for(A good : men) {
System.out.println("Good : " + good.name);
}
}
public static void main(String[] args) {
System.out.println("The A");
{
List<A> team = new ArrayList<A>();
{ A player = new A(); player.name = "John"; team.add(player); }
{ A player = new A(); player.name = "Paul"; team.add(player); }
testList(team);
}
System.out.println("The B");
{
List<B> bee = new ArrayList<B>();
{ B good = new B(); good.name = "George"; bee.add(good); }
{ B good = new B(); good.name = "Ringo"; bee.add(good); }
testList(bee);
}
}
}
class A { String name; }
class B extends A {}
Output:
The A
Good : John
Good : Paul
The B
Good : George
Good : Ringo
In case anyone are interested how it look like in C#
using System.Collections.Generic;
using System.Linq;
public class Covariance2 {
internal static void TestList(IEnumerable<A> men) {
foreach(A good in men) {
System.Console.WriteLine("Good : " + good.name);
}
}
public static void Main(string[] args) {
System.Console.WriteLine("The A");
{
IList<A> team = new List<A>();
{ A player = new A(); player.name = "John"; team.Add(player); }
{ A player = new A(); player.name = "Paul"; team.Add(player); }
TestList(team);
}
System.Console.WriteLine("The A");
{
IList<B> bee = new List<B>();
{ B good = new B(); good.name = "George"; bee.Add(good); }
{ B good = new B(); good.name = "Ringo"; bee.Add(good); }
TestList(bee);
}
}
}
class A { internal string name; }
class B : A {}
Java generics allow covariance only if explicitly declared via wildcards in order to provide stricter type safety. This works:
Iterable<? extends A> a = new ArrayList<A>();
Iterable<B> b = new ArrayList<B>();
a = b;
However, note that you now cannot add anything via the reference a since it's declared to contain instances of some specific but unknown class, which might be A or any subclass thereof. The behaviour of wildcards is often counter-intuitive and can get very complex, so they should be used in moderation.
Generics are not covariant in Java. You'll have to do it the old way, like it was when C# didn't support covariance in generics.
However, in Java, you can pretend a generic iterable is an iterable of anything, denoted by a question mark. A list of anything contains only objects.
Iterable<A> a = new ArrayList<A>();
Iterable<?> b = a;
There's a good reason why this kind of covariance in generic collections is a bad idea:
Suppose you do:
ArrayList<A> a = new ArrayList<A>();
ArrayList<B> b = new ArrayList<B>();
a.add(new A());
b = a;
B item=b.get(0);
Whoops - a function that was meant to return only objects of type B has returned type A. This clearly can't work. So the Java compiler disallows it in order to ensure type safety.
It's not a big deal though - easy workarounds are to just use the non-generic collection classes or restrict the generic type argument to the common superclass (A in this case).

Cast in List object

I have an interface A, class B inherits from interface A.
I have a list of objects:
List<B> myB;
List<A> myA;
I want to assign myB to myA but I get a error "Cannot implicit convert type 'B' to 'A':
myA = myB;
Please help me. Thanks.
You need to convert each element of the list. It cannot be automatically converted for you. Easiest would be Linq:
myA = myB.Cast<A>().ToList();
Update: This question: Why is this cast not possible? discusses it in more detail.
It might help you: Cast List<int> to List<string> in .NET 2.0
IList<T> is not covariant, where as IEnumerable<T> is, you can do the following..
void Main()
{
IEnumerable<B> myB= new List<B>();
IEnumerable<A> myA = myB;
}
public interface A
{
}
public class B :A
{
}
see this previous SO Question
You need to make a way to convert between type A and type B.
There is no way to assign a list of one type to another, unless the type B is the same as type A.
You can use the Cast<T> operator for derived types:
class A {}
class AA : A {}
List<AA> aas = new List<AA> {new AA()};
List<A> bunchofA = aas.Cast<A>().ToList();
This only works when casting to less derived types (from descendant to ancestor). This won't work:
List<A> bunchofA = new List<A> {new A()};
List<AA> aas = bunchofA.Cast<AA>.ToList();
Because the compiler cannot know what to do to make the extra bits that AA has from A.
You can also, in a rather contrived way, use implicit conversion:
class A
{
}
class B
{
public static implicit operator B(A a)
{
return new B();
}
public static implicit operator A(B a)
{
return new A();
}
}
List<B> bs = new List<B>{new B()};
List<A> bunchOfA = bs.Select(b => (A)b).ToList();
This will work in either direction, but might cause confusion, so it is better to create explicit conversion methods and use those.
That is correct. List is a list of Apples and List is a list of .. err .. batmans! You cannot try to put one into the other.
Technically, you cannot refer to one as the other!

.NET, C#, Reflection: list the fields of a field that, itself, has fields

In .NET & C#, suppose ClassB has a field that is of type ClassA.
One can easily use method GetFields to list ClassB's fields.
However, I want to also list the fields of those ClassB fields that themselves have fields.
For example, ClassB's field x has fields b, s, and i. I'd like to (programmatically) list those fields (as suggested by my comments in the code below).
class ClassA
{
public byte b ;
public short s ;
public int i ;
}
class ClassB
{
public long l ;
public ClassA x ;
}
class MainClass
{
public static void Main ( )
{
ClassA myAObject = new ClassA () ;
ClassB myBObject = new ClassB () ;
// My goal is this:
// ***Using myBObject only***, print its fields, and the fields
// of those fields that, *themselves*, have fields.
// The output should look like this:
// Int64 l
// ClassA x
// Byte b
// Int16 s
// Int32 i
}
}
Use the FieldInfo.FieldType to reflect over the type of the fields in your class. E.g.
fieldInfo.FieldType.GetFields();
Here is a complete sample based on your code that uses recursion in case you have ClassZ inside ClassA. It breaks if you have a cyclic object graph.
using System;
using System.Reflection;
class ClassA {
public byte b;
public short s;
public int i;
}
class ClassB {
public long l;
public ClassA x;
}
class MainClass {
public static void Main() {
ClassB myBObject = new ClassB();
WriteFields(myBObject.GetType(), 0);
}
static void WriteFields(Type type, Int32 indent) {
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
Console.WriteLine("{0}{1}\t{2}", new String('\t', indent), fieldInfo.FieldType.Name, fieldInfo.Name);
if (fieldInfo.FieldType.IsClass)
WriteFields(fieldInfo.FieldType, indent + 1);
}
}
}
The class that does this already exists! Take a look at the Microsoft C# Samples for Visual Studio: http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=csharpsamples&ReleaseId=8
Specifically, look at the ObjectDumper sample as it goes n-levels deep. For example:
ClassB myBObject = new ClassB();
...
ObjectDumper.Write(myBObject, Int32.MaxValue);
//Default 3rd argument value is Console.Out, but you can use
//any TextWriter as the optional third argument
It has already taken into account whether an object in the graph has been visited, Value types vs. object types vs. enumerable types, etc.
Try the following. It lets you control how deep you descend into the type hierarchy and should only descend into non-primitive types.
public static class FieldExtensions
{
public static IEnumerable<FieldInfo> GetFields( this Type type, int depth )
{
if( depth == 0 )
return Enumerable.Empty<FieldInfo>();
FieldInfo[] fields = type.GetFields();
return fields.Union(fields.Where( fi => !fi.IsPrimitive )
.SelectMany( f => f.FieldType.GetFields( depth -1 ) );
}
}
You need to write a recursive method that takes an object, loops through its fields (obj.GetType().GetFields()), and prints the value of a field of primitive type, and calls itself for a class (other than String).
You'll need a parameter for the indent size for use with recursion.
EDIT: You'll also need some mechanism to prevent a stack overflow for cyclic object graphs. I recommend placing a limit on the indent parameter.
Here's a naive implementation:
private static void ListFields(Type type)
{
Console.WriteLine(type.Name);
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
Console.WriteLine(string.Format("{0} of type {1}", field.Name, field.FieldType.Name));
if (field.FieldType.IsClass)
{
ListFields(field.FieldType);
}
}
}
Some things to note:
Prevent a stack overflow. That is if a -> b and b-> a then this will blow up. You can resolve this by only resolving down to a certain level
A string is a reference type but lots of people expect it to be more like a value type. So you might not want to call ListFields if the type is string.

Categories