C#: Interface instead of class in variable definition - c#

I have a following problem:
I have interface ILocation, which includes functions to get position of feature (in 2D grid). Not all classes can have this interface, but those, which do, are not related to each other (do not inherit from each other etc.). I.e. classes with this interface are Person, Item, BuildingBlock...
Now I have class Location, which includes variable "block". Basically anything can be there, with one condition: it must implement interface ILocation. How can I do that? I do not know, which class will be in this variable, and therefore have to specify it as an Object, but I know, it must implement ILocation. How can this be done?
In following example, I want to implement method Symbol, which is in ILocation interface.
public class Location :ILocation
{
public int X {get; set;}
public int Y {get; set;}
public Object block;
public Location (int x, int y, Object o)
{
X = x;
Y = y;
block = o;
}
public char Symbol()
{
return block.Symbol();
}
}
And this of course produces an Error, since instance block of class Object does not implement ILocation.
So - how can I tell C#, that in variable "block" can be any object, which implements ILocation?
Thanks
Zbynek

Declare block variable as location:
public ILocation block;
public Location (int x, int y, ILocation o)
{
X = x;
Y = y;
block = o;
}

Either what lazyberezovsky said or, if you also need to keep knowledge of the exact type of block, you can use something with generics like:
public class Location<TBlock> : ILocation
where TBlock : ILocation
{
public int X { get; set; }
public int Y { get; set; }
public TBlock block;
public Location(int x, int y, TBlock o)
{
X = x;
Y = y;
block = o;
}
public char Symbol()
{
return block.Symbol();
}
}

Replace Object with ILocation.
public ILocation block;
public Location (int x, int y, ILocation o)
So whenever you make object of Location you can pass any object which implements ILocation interface.
var book = new Book(); // Book implements ILocation.
var person = new Person(); // Person implements ILocation.
var table = new Table(); // Table doesn't implement ILocation.
var bookLocation = new Location(1, 2, book);
var personLocation = new Location(2, 3, person);
var tableLocation = new Location(2, 3, table); // Compile error as table doesn't implement ILocation,

Related

the "This" keyword front of constructor parentheses - C# [duplicate]

This question already has answers here:
Calling constructor from other constructor in same class
(3 answers)
Closed last month.
I know about "This" keyword and what is it working. but what is this using for?
public ReactiveProperty() : this(default(T))
{
}
I have seen this in UniRx Project. I just don't know the "This" keyword front of constructor.
I googled it but there is nothing to catch.
does anyone know?
This syntax is used to call another constructor defined in the class. Example from the docs:
class Coords
{
public Coords() : this(0, 0) // calls Coords(int x, int y) with x = 0 and y = 0
{ }
public Coords(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public override string ToString() => $"({X},{Y})";
}
var p1 = new Coords();
Console.WriteLine($"Coords #1 at {p1}");
// Output: Coords #1 at (0,0)
var p2 = new Coords(5, 3);
Console.WriteLine($"Coords #2 at {p2}");
// Output: Coords #2 at (5,3)

Can't access class field in another class

public class Vector
{
public int[] row = new int[2];
public Vector(int x, int y)
{
this.row[0] = x;
this.row[1] = y;
}
public int[] Row
{
get
{
return row;
}
}
}
public class Matrix<Vector>
{
public Vector[] rows = new Vector[2];
public Matrix(Vector v1, Vector v2){
this.rows[0] = v1;
this.rows[1] = v2;
}
public void Transform()
{
foreach (Vector v in rows)
{
Console.WriteLine(v.row[0]);
}
}
}
I'm getting 'Vector' does not contain a definition for 'row' and I have no idea why. It's set to public and I'm iterating over vector objects. What am I doing wrong here?
This is my first time using c#, coming from python so please don't mind the code if it doesn't make sense. Just toying with classes and syntax
here as you have written in your question,
public class Matrix<Vector>
means, your class Matrix is generic, and whatever type you will pass while creating an instance of Matrix, code of this class will take that type as Vector .
Note that your class Vector is total different type than the type Vector in Matrix class.
For ex.
if your create an object of matrix like this,
Matrix<string> m = new Matrix<string> ("amit", "maheshwari");
this will be valid and for this instacne of Matrix, Vector will be string. and yes string does not contain a definition for 'row' and so does Vecotr.
So, maybe you are misusing this class.
Or if you have created this class by your self and you want to perform what you have shown in question, there is no need to make this class generic.
public class Matrix
{
//so now this array of vector will be of class Vector
public Vector[] rows = new Vector[2];
public Matrix(Vector v1, Vector v2){
this.rows[0] = v1;
this.rows[1] = v2;
}
public void Transform()
{
foreach (Vector v in rows)
{
Console.WriteLine(v.row[0]);
}
}
}
public class Matrix<TVector> where TVector : Vector
{
public TVector[] rows = new TVector[2];
public Matrix(TVector v1, TVector v2)
{
this.rows[0] = v1;
this.rows[1] = v2;
}
public void Transform()
{
foreach (TVector v in rows)
{
Console.WriteLine(v.row[0]);
}
}
}
Thank you for John and other friends for reply quick answer. you must use TVector.

Returning a reference of a struct instead of a copy on C# 3.0?

I have this code:
using System;
using System.Collections.Generic;
using UnityEngine;
public interface HaveId
{
int id { get; }
}
public struct BusinessData : HaveId
{
// business type data
public int graphic_asset_id;
public string name;
public int id { get; set; }
}
public class LookupHelper<T> where T: HaveId
{
private T[] _list;
public T[] list
{
get { return _list; }
set { _list = value; _mapToDictionary(); }
}
private Dictionary<int, int> idxById = new Dictionary<int, int>();
public LookupHelper(){}
private void _mapToDictionary()
{
if(idxById.Count > 0) idxById = new Dictionary<int, int>();
for(var z =0 ; z < list.Length; ++z)
{
idxById[list[z].id] = z;
}
}
public bool IsIdExists(int id)
{
return idxById.ContainsKey(id);
}
public T ById(int id) // is this a reference?
{
var idx = idxById[id];
if (idx >= list.Length) throw new Exception(
String.Format("Invalid Index: {0} >= {1} on {2}",idx.ToString(),list.Length.ToString(), typeof(T).Name)
);
return list[idx];
}
}
And the test code:
LookupHelper<BusinessData> bd = new LookupHelper<BusinessData>();
bd.list = new BusinessData[]
{
new BusinessData{id = 1, name = "test"},
new BusinessData{id = 2, name = "test2"},
};
bd.ById(1).name = "foo";
This give an error: "Cannot modify struct member when accessed struct is not classified as a variable"
How can I change the value of first BusinessData and keep the array still allocated on a contiguous memory (array of struct, needed for cache locality)?
This should be a simple matter of splitting it up into a few lines. Extract the object to get a copy, modify the copy, then overwrite it in the array:
BusinessData bsd = bd.ById(1);
bsd.name = "foo";
bd.SetById(1, bsd);
Of course, you'll need to write that SetById method to reinsert things into the array:
public void SetById(int id, T obj)
{
Int32 idx = idxById[id];
list[idx] = obj;
}
As you know C# borrowed something’s from C and Java. But not everything.
In C, you can create a place for struct on the stack or the heap. On the heap, I can then pass a pointer around and change the content. Very powerful.
But C# emphasizes ease of memory management via garbage collection. To make it easy, C# has the concept of boxing value types into System.Object. Additional details, can be found on Microsoft C# Programming Guide on Boxing and unboxing.
So when you access the value type in your list, you have to explicitly unbox the value. Therefore it’s a copy of the item in the list. You can do what #Nyerguds suggested.
But to make life easy, why not turn your BusinessData into a class?

Cannot convert from class to generic interface

EDIT: Updated to include actual code.
I am having an issue with some custom generic interfaces and I am not entirely sure what to do. The error I'm getting is:
Cannot convert from Map to IMap<ICell>
That error pops up when I try to pass Map as a parameter to a method that accepts IMap<ICell>. I have pasted sample code below. Just to be clear, FieldOfView doesn't use anything that hasn't been defined in ICell or IMap.
public class Map : IMap<Cell>
{
private FieldOfView _fieldOfView;
public int Width { get; }
public int Height { get; }
public Map(int width, int height)
{
Width = width;
Height = height;
_fieldOfView = new FieldOfView(this as IMap<ICell>);
_fieldOfView = new FieldOfView((IMap<ICell>)this);
}
public IEnumerable<Cell> GetAllCells()
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
yield return GetCell(x, y);
}
}
}
public Cell GetCell(int x, int y)
{
return new Cell(x, y);
}
public void Copy(IMap<Cell> sourceMap)
{
// ...
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var cell in GetAllCells())
{
sb.Append(cell.ToString());
}
return sb.ToString();
}
}
public interface IMap<T> where T : ICell
{
int Width { get; }
int Height { get; }
IEnumerable<T> GetAllCells();
T GetCell(int x, int y);
void Copy(IMap<T> sourceMap);
}
public class Cell : ICell
{
public int X { get; }
public int Y { get; }
public Cell(int x, int y)
{
X = x;
Y = Y;
}
public override string ToString()
{
return "overloaded";
}
}
public interface ICell
{
int X { get; }
int Y { get; }
}
public class FieldOfView
{
private readonly IMap<ICell> _map;
public FieldOfView(IMap<ICell> map)
{
_map = map;
}
public void DoStuff()
{
foreach (var cell in _map.GetAllCells())
{
// ...
}
}
}
This is similar to this stack overflow question, but a little different. I tried implementing an interface IMap as well as IMap<T> : IMap where T : ICell, but am having issues with that as well.
Lastly, I'm not sure if this is solvable with co/contravariance, but I am using C#3.0 so that is out of the picture for me (unless switching versions is the only way).
I think it would be fine with an implicit / direct cast?
_fieldOfView = new FieldOfView(this as IMap<ICell>); // or
_fieldOfView = new FieldOfView((IMap<ICell>)this);
But if there is a better way, I would like to do that. Resharper does throw me a warning when I cast Map to IMap<ICell> saying:
Suspicious cast: there is no type in the solution which is inherited from both Map and IMap<ICell>.
EDIT2: Look's like neither of the casts worked. I've decided instead to make Map be derived from IMap and just create the Cell objects where needed in the code.
Thanks #Rob and #MK87 for your help!
No, IMap<Cell> is not the same as IMap<ICell>, so this line:
_fieldOfView = new FieldOfView(this as IMap<ICell>);
will always pass null as parameter.
Yes, this is definitely solvable with variance.
For example, you can have:
IEnumerable<object> list = new List<string>();
since list is IEnumerable<outT>, that means that every IEnumerable<TT> with TT that derives from T is a valid value for list. So the List doesn't have to be of object, it can be of any derived type.
But because you can't use variance, we need another hack.
Possible solution: instead of deriving Map from IMap<Cell>, derive it from IMap<ICell>. You'll have only to correct some points, for example the return type of GetCell() must become ICell instead of Cell. Is it feasable for you?

Need help to understand polymorphism

The classes below consist of
A - father class
B - Child class
Holder - Contains a list of A's
I want to reach a child property from the list of fatherobjects. Why cant I do this? Or better question, how do I do this?
public class A
{
public int var = 0;
}
public class B : A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public B()
{
}
public B(B p_B)
{
Property1 = p_B.Property1;
Property2 = p_B.Property2;
}
}
class Holder
{
private List<A> m_Objects = new List<A>();
public void AddObject(A p_Object)
{
m_Objects.Add(p_Object);
}
public void AddObjectProperty1(B p_B)
{
// At this point, m_Objects holds a B-object. And I want to add the value from Property1
// but there is no Property1 in the A-class so I cant do this. How do I use the base.values from
// a statement like the one below?
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
if (index > -1)
m_Objects.ElementAt(index).Property1 += p_B.Property1;
}
}
class Program
{
static void Main(string[] args)
{
// Class to hold the objects
Holder h = new Holder();
// Create a B object
B b = new B();
b.Property1 = 1;
b.Property2 = 2;
// Place a new instance of the B-object in a list of A's
h.AddObject(new B(b));
// Add the value from Property1 to the value in the b-object in the a-list. :P
h.AddObjectProperty1(b);
Console.WriteLine(++b.var);
Console.ReadLine();
}
}
You can use type casting:
(m_Objects[i] as B).Property1
Or
((B)m_Objects[i]).Property1
At compile-time there is no possibility for the compiler to know, you would only add Bs to your list of As. So there is no guarantee whatsoever that each item in the following query is an instance of B and thus has Property1
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
First possibilty is casting as in Artyom's answer. But this will fail if you not all of the elements in the List are really Bs. So if you rely on all Elements in m_Objects to be instances of B, why don't you just use List<B> m_Objects?
If you need the mixed list, you have to do a type-check in the query to ensure, you are dealing with an instance of Bbefore casting.
int index = m_Objects.FindIndex(item => (item is B) && (item as B).Property1 == p_B.Property1);
See this DotNetFiddle Example

Categories

Resources