Need help understanding a code - c#

so this program I'm on has sprites. Each sprite has a limit to the number of frames its sprite can have, and I'm trying to figure out how to learn that limit so I can modify it. But the code that I've been reading is really difficult for me. I've been reading up on some of the stuff it uses (like Dictionary and Out), but when I try to apply that reading to the code, it just falls apart.
So uh, if someone would be willing to kind of dissect the code and tell me what it says, that would be great. The full of it can be found here, but this is what I'm trying to read in particular:
class FrameData {
Dictionary<FrameType, Dictionary<Enums.Direction, int>> frameCount;
}
public FrameData() {
frameCount = new Dictionary<FrameType, Dictionary<Enums.Direction, int>>();
}
public void SetFrameCount(FrameType type, Enums.Direction dir, int count) {
if (frameCount.ContainsKey(type) == false) {
frameCount.Add(type, new Dictionary<Enums.Direction, int>());
}
if (frameCount[type].ContainsKey(dir) == false) {
frameCount[type].Add(dir, count);
} else {
frameCount[type][dir] = count;
}
}
public int GetFrameCount(FrameType type, Enums.Direction dir) {
Dictionary<Enums.Direction, int> dirs = null;
if (frameCount.TryGetValue(type, out dirs)) {
int value = 0;
if (dirs.TryGetValue(dir, out value)) {
return value;
} else {
return 0;
}
} else {
return 0;
}
}

//This bit declares the class. note that all the stuff after it should come inside the open and closed curly braces, so there's already a syntax error here.
class FrameData {
Dictionary<FrameType, Dictionary<Enums.Direction, int>> frameCount;
}
// Public parameterless constructor. This gets called when someone creates an instance of the class, e.g. FrameData myframe = new FrameData()
public FrameData() {
// initialize the instance variable frameCount with a new dictionary that takes a FrameType as the key and another dictionary of Enums.Direction and ints as key and value
frameCount = new Dictionary<FrameType, Dictionary<Enums.Direction, int>>();
}
// Public method for adding or replacing a key and its value in the frameCount dictionary
public void SetFrameCount(FrameType type, Enums.Direction dir, int count) {
// adds a new one if it didn't already have that key
if (frameCount.ContainsKey(type) == false) {
frameCount.Add(type, new Dictionary<Enums.Direction, int>());
}
// adds a new key to the inner dictionary if it's not there
if (frameCount[type].ContainsKey(dir) == false) {
frameCount[type].Add(dir, count);
} else {
// otherwise just replaces what was already there
frameCount[type][dir] = count;
}
}
// fetches the nested value from the inner dictionary given the type and direction
public int GetFrameCount(FrameType type, Enums.Direction dir) {
Dictionary<Enums.Direction, int> dirs = null;
if (frameCount.TryGetValue(type, out dirs)) {
int value = 0;
if (dirs.TryGetValue(dir, out value)) {
return value;
} else {
return 0;
}
} else {
return 0;
}
}

Related

Overwriting an array entry when it has a duplicate key

I'm writing a small programm right now in which I made a Paar class, where one object consists of a key and a value
class Paar
{
private object value1;
public Paar(string key, object value1)
{
this.key = key;
this.value = value1;
}
public string key;
public object value;
}
I made a Put and a Get method for the class. The Put method parses a new entry in the first open slot it finds and the Get method can be used to print an entry by calling the key, they're as following
private Paar[] getArray = new Paar[10];
public void Put(string key, object value)
{
int i = 0;
while (true)
{
if (getArray[i] == null)
{
break;
}
else
{
i++;
if (i == 10)
{
throw new Exception("All slots full");
}
}
}
getArray[i] = new Paar(key, value);
}
public object Get(string key)
{
for (int i = 0; i <= 9; i++)
{
Paar currentElement = getArray[i]
if (currentElement.key == key)
{
return currentElement.value;
}
}
throw new Exception("Invalid key");
}
"Problem" is, that when I have two entries with the same key, I can only print the first entry, while I'd like to add a function to the Put method that overwrites previous entries with the same key and prints the most recent entry.
E.g:
newMap.Put("Key2", "Value1"); newMap.Put("Key2", "Value2"); newMap.Put("Key2", "Value3");
Console.WriteLine(newMap.Get("Key2"));
would currently print Value1, while I'd like it to print Value3. Is there any way to achieve this?
Try following
public void Put(string key, object value)
{
for (var i = 0; i < getArray.Length; ++i)
{
if (getArray[i] == null || getArray[i].key == key)
{
getArray[i] = new Paar(key, value);
break;
}
if(i == getArray.Length - 1)
throw new Exception("All slots full");
}
}
I implemented tchelidze's answer since it was technically correct, but when later implementing a Remove method it didn't work properly all the time since it could also parse the duplicate key's entry into an empty slot if there happened to be one before the duplicate key's slot, because it either checked for an empty slot or a matching key. So I improved the function to go through two seperate loops.
public void Put(string key, object value)
{
for (int i = 0; i < getArray.Length; i++)
{
if (getArray[i] != null && getArray[i].key == key)
{
getArray[i] = new Paar(key, value);
return;
}
}
for (int i = 0; i < getArray.Length; i++)
{
if (getArray[i] == null)
{
getArray[i] = new Paar(key, value);
break;
}
else
{
if (i >= getArray.Length)
{
throw new Exception("All slots full");
}
}
}
}

Passing references (And Unity's WWW.progress) to Coroutines/IEnumerators

I've made a coroutine within C# using Unity 5 and I'd like to pass a reference to it. It didn't seem to work so I made a test script to try to isolate the following error.
error CS1623: Iterators cannot have ref or out parameters
Here's the test script:
using UnityEngine;
using System.Collections;
public class TEMP : MonoBehaviour {
// Use this for initialization
void Start () {
float var = 3.141f;
StartCoroutine ( test (ref var) );
}
IEnumerator test (ref float value) {
for (int i = 1; i <= 10; i++) {
Debug.Log (value);
yield return null;
}
}
}
In addition, on my actual script, I'm using Unity's WWW class to download something, and I also get this error when I pass www.progress as a reference:
A property or indexer 'UnityEngine.WWW.progress' may not be passed as 'ref' or 'out' parameter
Remove the ref from the function arguments.
// Use this for initialization
void Start () {
float var = 3.141f;
StartCoroutine ( test (var) );
}
IEnumerator test (float value) {
for (int i = 1; i <= 10; i++) {
Debug.Log (value);
yield return null;
}
}
Based on your requirement you could do something like below with an out parameter. I'm not exactly sure how you are intending to use these methods but I think you are getting the wrong idea about ref arguments and how they work.
class Program
{
static void Main(string[] args)
{
float var = 3.14f;
StartCoroutine(test(var), out var);
}
static IEnumerator test(float value)
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(value);
yield return value + 1;
}
}
static void StartCoroutine(IEnumerator test, out float update)
{
update = 0;
while (test.MoveNext())
{
update++;
Console.WriteLine("Executing..." + update);
}
}
}
However you are never going to be able to pass a ref or out parameter to the interator.
Consider that
IEnumerator test (float value)
{
for (int i = 1; i <= 10; i++)
{
Debug.Log(value);
yield return null;
}
}
Is syntactic sugar for something like:
private class Iterator : IEnumerable<object>, IEnumerator<object>
{
private int _state;
private int _threadId = Environment.CurrentManagedThreadId;
private object _current;
private float _value;
int i;
public Iterator(float value)
{
_value = value;
}
public object Current‎
{
get { return _current; }
}
object IEnumerator.Current
{
get { return _current; }
}
public IEnumerator<object> GetEnumerator()
{
// If we're on the same thread and its the first call, reuse this object as the enumerator
// otherwise create a fresh one for new call (so we don't have buggy overlaps) or a different
// thread (to avoid a race on that first call).
Iterator iter = _state == 0 && _threadId == Environment.CurrentManagedThreadId ? this : new Iterator(_value);
iter._state = 1;
return iter;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public bool MoveNext()
{
switch(_state)
{
case 1:
i = 1;
_state = 2;
goto case 2;
case 2:
if (i <= 10)
{
Debug.Log(_value);
_current = null;
++i;
return true;
}
_state = -1;
break;
}
return false;
}
public void Dispose()
{
}
public void Reset()
{
throw new NotSupportedException();
}
}
private IEnumerator test(float value)
{
return new Iterator(value);
}
Now, consider that your float parameter has become a float field in the implementation. Since you can't have a ref field, you can't have it as syntactic sugar for what looks like a ref parameter.
Hence your approach not only won't work (C# won't do it for you with yield taking away a lot of the coding) but can't work.
You'll need to box the float in some way, whether you are holding onto a object reference to the same float, that as a reference-type can be updated by the iterator, or a typed box like:
private class TypedBox<T> where T : struct
{
public T Value { get; set; }
public TypedBox(T value)
{
Value = value;
}
}
That again allows you to access the value via a reference-type, but without the casting cost.
More often its more useful just to have the value iterated based on any values passed in.

Dictionary Immutable Issue alternative in C#

Not sure of the best alternative to dictionaries in this scenario - objects or arrays.
I need to change the value of the dictionary(or whatever else) depending on whether the id/key exists, adding to the existing value if the id parsed in does exist, never the key/id - what would be the best alternative?
Code
Dictionary<int, int> total = new Dictionary<int, int>();
// elsewhere in a function...
ArrayManager(total, id, value);
public void ArrayManager(Dictionary<int,int> items, int id, int val)
{
int i = 0;
bool found = false;
foreach(var item in items)
{
if(item.Key == id)
{
item.Value += val; // immutable issue stops this from working
found = true;
break;
}
}
if(found == false)
{ // do something }
}
If you're trying to increment the value identified by a given key:
public void ArrayManager(Dictionary<int,int> items, int id, int val)
{
int currentVal = 0;
if (items.TryGetValue(id, out currentVal))
{
int newVal = currentVal + val;
items[id] = newVal;
// Do something else
}
I believe what you are trying to do is:
if(item.Key == id)
{
items[item.Key]+= val;
}

C# - Dictionary with Behaviour of a Ring List?

I need a ring list dictionary that can store key and item. Capacity = 50 and when I add #51 the first item must be removed. Basically it must be a dictionary that behaves like a ring list.
Is there something in .NET Framework that can do that ? Or do I have to write it by myself ?
You won't find anything built-in I think but you can easily implement one using OrderedDictionary
OrderedDictionary maintains items in order which they are inserted. Whenever you reach the limit/capacity you can remove the first item.
or use an extension method :
EDIT :
because
latest added entry ends up being returned first.
so
u can remove the first item like :
dictionary.Remove(dictionary.Last().Key);
& so your extension method is :
addExtension(this Dictionary<string, object> dictionary, string key, object value)
{
if(dictionary.Count == 50)
dictionary.Remove(dictionary.Last().Key);
dictionary.Add(key, value);
}
Try this:
class Program
{
static void Main(string[] args)
{
var rD = new RingDictionary(50);
for (int i = 0; i < 75; i++)
{
rD.Add(i, i);
}
foreach (var item in rD.Keys)
{
Console.WriteLine("{0} {1}", item, rD[item]);
}
}
}
class RingDictionary : OrderedDictionary
{
int indexKey;
int _capacity = 0;
public int Capacity
{
get { return _capacity; }
set
{
if (value <= 0)
{
var errorMessage = typeof(Environment)
.GetMethod(
"GetResourceString",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic,
null,
new Type[] { typeof(string) },
null)
.Invoke(null, new object[] {
"ArgumentOutOfRange_NegativeCapacity"
}).ToString();
throw new ArgumentException(errorMessage);
}
_capacity = value;
}
}
public RingDictionary(int capacity)
{
indexKey = -1;
Capacity = capacity;
}
public new void Add(object key, object value)
{
indexKey++;
if (base.Keys.Count > _capacity)
{
for (int i = base.Keys.Count-1; i >Capacity-1 ; i--)
{
base.RemoveAt(i);
}
}
if (base.Keys.Count == _capacity)
{
base.RemoveAt(indexKey % _capacity);
base.Insert(indexKey % _capacity, key, value);
}
else
{
base.Add(key, value);
}
}
}

Declaring Inner dictionary comparer C#

I have a dictionary as follows
Dictionary<ulong, Dictionary<byte[], byte[]>> Info;
And the inner dictionary holds a byte[] array as a key.
I am unable to understand how to declare the constructor for a the Info dictionary. For the inner key comparison I have ByteArrayComparer,
public class ByteArrayComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] left, byte[] right)
{
if (left == null || right == null)
{
return left == right;
}
if (left.Length != right.Length)
{
return false;
}
for (int i = 0; i < left.Length; i++)
{
if (left[i] != right[i])
{
return false;
}
}
return true;
}
public int GetHashCode(byte[] key)
{
if (key == null)
throw new ArgumentNullException("key");
int sum = 0;
foreach (byte cur in key)
{
sum += cur;
}
return sum;
}
}
Which I picked up from SO Here
Please advise
The specification for the comparer wouldn't be part of the Info initialization directly - it would be when you create a value to put in the outer dictionary. For example:
// It's stateless, so let's just use one of them.
private static readonly IEqualityComparer<byte[]> ByteArrayComparerInstance
= new ByteArrayComparer();
Dictionary<ulong, Dictionary<byte[], byte[]>> Info
= new Dictionary<ulong, Dictionary<byte[], byte[]>();
....
...
Dictionary<byte[], byte[]> valueMap;
if (!Info.TryGetValue(key, out valueMap))
{
valueMap = new Dictionary<byte[], byte[]>(ByteArrayComparerInstance);
Info[key] = valueMap;
}
...
When created your Info doesn't have any dictionaries inside so u can't realy define comparere at that step. You have to do this for each item added into Info object.

Categories