I created the following struct to keep track of all my network IDs I use for my game:
public struct NetworkId {
private static int _availibleId = 1;
private int _id;
public static implicit operator int(NetworkId i) {
if (i._id == 0) {
i._id = _availibleId++;
}
return i._id;
}
}
I initialize the ID at the moment someone tries to access it. But my problem now is, when I use the id like in the following example, the ID gets reassigned every time.
public class TestObject {
private NetworkId _id;
public NetworkId Id { get { return _id; } }
public void Create {
NetworkManager.SendPacket(new Packets.CreateObject(Id));
}
}
I can't wrap my head around what is happening here. Thank you for your help!
Does it need to be a struct? With class semantics do this:
public class NetworkId
{
private static int _availibleId = 1;
public int Id { get; } = _availibleId++;
public static implicit operator int(NetworkId i)
{
return i.Id;
}
}
void Test() {
int A = new NetworkId(); //A=1
int B = new NetworkId(); //B=2
}
Related
First time poster...
New to C# and Generics and I have been experimenting by creating a simple series of Object Tables for read-only data entries.
On my Generic Insert routine I increment a static Id variable to ensure it is always unique. To try and prevent it being modified I set it to protected but the Generic class which then throws a compile error stating that Id can't be accessed.
I am struggling to find out why exactly as I thought "where T : DBEntity" would allow this.
Thanks in advance:
public class DBEntity
{
public int Id { get; protected set; }
}
public class Table<T> where T : DBEntity
{
static int _id = 0;
private readonly List<T> _set = new List<T>();
public IEnumerable<T> Set() { return _set; }
public void Insert(T item)
{
_id++;
item.Id = _id; //when set to protected it is inaccessible
_set.Add(item);
}
}
You're protecting the ID, so you can't set it. It's honestly as simple as that.
Also doing a generic of Table, and tying the generic to a concrete class buys you nothing. Consider an interface instead.
You could fix your issue as the following:
public interface IDatabaseItem
{
int? Id { get; }
SetID(int value);
}
public class DBEntity : IDatabaseItem
{
public int? Id { get; private set; }
public void SetID(int value)
{
if (Id == null)
{
Id = value;
}
else
{
throw new Exception("Cannot set assigned Id; can only set Id when it is not assgined.");
}
}
}
public class Table<T> where T : IDatabaseItem
{
static int _id = 0;
private readonly List<T> _set = new List<T>();
public IEnumerable<T> Set() { return _set; }
public void Insert(T item)
{
if (item.Id == null)
{
_id++;
item.SetID(_id);
_set.Add(item);
}
else
{
//Handle this case. Something else set the ID, yet you're trying to insert it. This would, with your code, imply a bug.
}
}
}
I want that a.ID() returns 0 and b.ID() returns 1 and here is my code:
public class A {
public static int id;
public int ID() {return id;}
}
public class B : A { }
public class Main {
void Program() { //This executes when I execute the program
A.id = 0;
B.id = 1;
}
}
But it doesn't work, this also doesn't work:
public class A {
public static int id;
public int ID() {return id;}
}
public class B : A {
public new static int id; //id is actually 1 but ID() is still 0
}
public class Main {
void Program() { //This executes when I execute the program
A.id = 0;
B.id = 1;
}
}
How can I fix this?
You can create two static variables and one virtual property
public class A
{
private static int _idA;
public virtual int Id
{
get { return _idA; }
set { _idA = value; }
}
}
public class B : A
{
private static int _idB;
public override int Id
{
get { return _idB; }
set { _idB = value; }
}
}
Or one property and use new keyword to override it
public class A
{
public static int Id { get; set; }
}
public class B : A
{
public static new int Id { get; set; }
}
To test first solution you can try following
static void Main(string[] args)
{
A test = new B();
new B().Id = 3;
new A().Id = 2;
test.Id = 1;
Console.WriteLine(test.Id + " " + new B().Id + " " + new A().Id);
Console.ReadKey();
}
If you can accept these rules:
The numbers can be anything, ie. any legal int
They don't have to start at 0
They don't have go up by 1 for each new unique type
The numbers are allowed to change between executions of your program
ie. you run your program and type A returns id 33554436
You change the program (somewhere else) and rerun, now type A returns id 33554437 (a different value)
then here is a way to get your ID:
public class Base
{
public int ID
{
get
{
return GetType().MetadataToken;
}
}
}
You don't need to override this property to get unique id's for each type but you can no longer guarantee what the values will be, here's example output from two such derived classes:
33554436
33554437
If I added a new type between those two and reran, I got:
33554436
33554438
If you're afraid the constant trip to reflection is going to be expensive here is an alternative declaration:
public class Base
{
private readonly Lazy<int> _ID;
protected Base()
{
_ID = new Lazy<int>(() => GetType().MetadataToken);
}
public int ID
{
get
{
return _ID.Value;
}
}
}
You can make the ID method virtual and override it in the B class like this:
public class A
{
public static int id;
public virtual int ID() { return id; }
}
public class B : A
{
public static int id;
public override int ID()
{
return id;
}
}
Here is another way to do it that uses Reflection:
public class A
{
public static int id;
public int ID()
{
return (int)this.GetType()
.GetField("id", BindingFlags.Static | BindingFlags.Public)
.GetValue(null);
}
}
public class B : A
{
public static int id;
}
This way, you don't have to override the ID method on each subclass. However, you still need to defined a static id field in each subclass.
I want to create a class with custom callback function. How can i do that?
How to implement this pseudocode in C#?
public class SomeClass
{
public Function {get;set}
}
public class SomeClass1
{
private int DoInt () { return 1;}
private void Do () { }
public int value {get; set {/*callback function*/someClass.Function();}}
public SomeClass someClass {get; set;}
public SomeClass1 ( bool b)
{
if (b) someClass = DoInt else someClass = Do;
}
}
You can use delegates. Just create delegate-field, and Init it in constructor.
You can use the Func and/or Action types to have functions as variables:
public class SomeClass
{
private Action mySavedFunction;
private int DoInt () { return 1;}
private void Do () { }
public int value { get; set { mySavedFunction(); } }
public SomeClass ( bool b)
{
if (b)
mySavedFunction = () => this.DoInt();
else
mySavedFunction = this.Do;
}
}
But maybe you just want nullable type? Use int? as a return type for your function to be able to return both null and int values.
The following code shows how I am trying to serialize/deserialze a List using Protobuf-Net. Method getNewItem() returns an object of ItemsStore, which is added to the List.
// Create an empty list
private ItemsStoreList text;
// Add some elements to the list
lock (text.SyncRoot)
{
text.AddItem(getNewItem());
text.AddItem(getNewItem());
text.AddItem(getNewItem());
}
// Serialize
var file = File.Create("testfile.bin");
Serializer.Serialize<ItemsStoreList>(file, text);
// Deserialize
ItemsStoreList textNew = Serializer.Deserialize<ItemsStoreList>(file);
After I run this code, the list contained in object textNew is always empty. Object textNew is instantiated from class ItemsStoreList, which is shown below:
[ProtoContract]
public class ItemsStoreList
{
[ProtoMember(1)]
private List<ItemsStore> m_listData;
private readonly object m_SyncRoot = new object();
public ItemsStoreList()
{
m_listData = new List<ItemsStore>();
}
public void AddItem(ItemsStore item)
{
m_listData.Add(item);
}
public object SyncRoot
{
get { return this.m_SyncRoot; }
}
public int Count
{
get { return m_listData.Count; }
}
public ItemsStore getItem(int idx)
{
return (ItemsStore)m_listData[idx];
}
public void Clear()
{
m_listData.Clear();
}
}
[ProtoContract]
public class ItemsStore
{
[ProtoMember(1)]
public myStruct m_Text;
[ProtoMember(2)]
public ulong m_Time;
public ItemsStore(myStruct newText, ulong newTime)
{
m_Text = newText;
m_Time = newTime;
}
public myStruct Text
{
get { return m_Text; }
}
public ulong Time
{
get { return m_Time; }
}
}
[ProtoContract]
public struct myStruct
{
[ProtoMember(1)]
public uint var1;
[ProtoMember(2)]
public byte var2;
[ProtoMember(3)]
public byte[] var3;
[ProtoMember(4)]
public string var4;
}
The first thing I note is that you have not rewound the stream; adding this (between serialize and deserialize) changes the behaviour:
file.Position = 0;
We now get an exception relating to the ItemsStore constructor, so we can instruct protobuf-net to ignore that constructor completely:
[ProtoContract(SkipConstructor = true)]
public class ItemsStore
Now we get 3 items back:
System.Console.WriteLine(textNew.Count);
which outputs:
3
Further probing shows that it is most likely fetching the other data too:
for (int i = 0; i < textNew.Count; i++)
{
var item = textNew.getItem(i);
System.Console.WriteLine(item.m_Text.var1);
System.Console.WriteLine(item.m_Time);
}
I will, however, add the obligatory warning about mutable structs and public fields.
Suppose class A as:
public class A
{
private string _str;
private int _int;
public A(string str)
{
this._str = str;
}
public A(int num)
{
this._int = num;
}
public int Num
{
get
{
return this._int;
}
}
public string Str
{
get
{
return this._str;
}
}
}
I want to hide Str property when i construct class A as
new A(2)
and want to hide Num property when i construct class A as
new A("car").
What should i do?
That isn't possible with a single class. An A is an A, and has the same properties - regardless of how it is constructed.
You could have 2 subclasses of abstract A, and a factory method...
public abstract class A
{
class A_Impl<T> : A
{
private T val;
public A_Impl(T val) { this.val = val; }
public T Value { get { return val; } }
}
public static A Create(int i) { return new A_Impl<int>(i); }
public static A Create(string str) { return new A_Impl<string>(str); }
}
But : the caller will not know about the value unless they cast it.
use generics
public class A<T>
{
private T _value;
public A(T value)
{
this._value= value;
}
public TValue
{
get
{
return this._value;
}
}
}