Just want to get some advice on what is the best practice to share a struct.
I have a number of internal classes that I would like to use the same instance of a struct. Instead of passing struct as a param is there an alternative?
Thanks in advance.
I think you are asking on how to create a reference or a pointer to a struct. In C# you can do this only with structs made up of only intrinsic value types (int, byte, float, double, char)
Take the following example and compile it with unsafe option
public struct Data
{
public int id;
public double x;
}
unsafe class A
{
Data* data;
public A(Data* data)
{
this.data = data;
}
public int ID { get { return data->id; } set { data->id = value; } }
}
unsafe class B
{
Data* data;
public B(Data* data)
{
this.data = data;
}
public double X { get { return data->x; } set { data->x = value; } }
}
unsafe class Program
{
static void Main(string[] args)
{
Data store = new Data();
A a = new A(&store);
B b = new B(&store);
a.ID = 100;
b.X = 3.33;
Console.WriteLine("id={0} x={1}", store.id, store.x);
}
}
It will print out "id=100 x=3.33" even though the value type variable store is never directly assigned those values. Both classes contain a reference to the struct and can manipulate its values.
Want to learn more about pointers to structs, look at this article, or this MSDN document. Yes, the above is legit C# code and despite the unsafe keyword is rather reliable and robust when properly coded. Oh, and it is wicked fast too.
You should consider using structs only for defining data structures that looks like basic types like strings, int etc..
Those structs are treated as value types in opposition of classes that are treated as reference types.
Related
I've got a struct stored in a readonly field, nested in a few levels of objects (all in code that is outside of my control), that I am accessing in a function. For example:
struct Surprise { public readonly int a, b, c; }
struct Gizmo { public readonly Surprise surprise; }
struct Bobble { public readonly Gizmo gizmo; }
struct Thing { public readonly Bobble bobble; }
class Gift { public readonly Thing thing; }
void Function (Gift gift) {
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
}
Purely to avoid having to type out gift.thing.bobble.gizmo.surprise every time I use it, I'd like to assign that to a local variable with a shorter name. However, I also don't need to copy the struct, so I'd like to avoid that:
void Function (Gift gift) {
{ // (A) this is what i'm trying to not type out:
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
}
{ // (B) i can do this, but i don't *need* to copy, so i'd like to avoid:
Surprise s = gift.thing.bobble.gizmo.surprise;
int contrived = s.a * s.b + s.c;
}
{ // (C) what i *want* to do is something like this:
ref Surprise s = ref gift.thing.bobble.gizmo.surprise;
int contrived = s.a * s.b + s.c;
}
}
However, it seems that variation (C) there is not allowed, and so doesn't compile:
CS0192 A readonly field cannot be used as a ref or out value
(except in a constructor)
My question is: Is there a way to create a local variable that refers to a readonly value-typed field and doesn't copy it (or some other approach to save myself some typing)?
I'm fairly new to C#, coming from C++. If you're familiar with C++ I'm essentially looking for the equivalent of:
const Surprise &s = gift->thing.bobble.gizmo.surprise;
Also: Would it even make a difference, or is the compiler smart enough to not create a copy in (B) above?
By the way, I did, after much struggle, come up with this nightmare:
delegate void Hack (in Surprise s);
void Function (Gift gift) {
((Hack)((in Surprise s) => {
int contrived = s.a + s.b + s.c;
...;
}))(gift.thing.bobble.gizmo.surprise);
}
I'm not interested in that as an option, though, for hopefully obvious reasons. Also I'm not actually sure if that even avoids a copy.
How about an extension method.
public static class GiftExtension
{
public static int Sum(this Gift gift)
{
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
return contrived;
}
public static int Sum(this Surprise surprise)
{
int contrived = surprise.a +
surprise.b +
surprise.c;
return contrived;
}
}
then in your method, you can have
void Function(Gift gift)
{
{
//(A) was trying to use a pointer to access the memory location, couldn't get it to work!
//unsafe
//{
// Surprise* ps = &(gift.thing.bobble.gizmo.surprise);
//}
}
//(B)
{
int contrived = gift.Sum();
}
{
int contrived = gift.thing.bobble.gizmo.surprise.Sum();
}
}
Create a readonly property to access the value you want.
public struct Surprise
{
get
{
return gift.thing.bobble.gizmo.surprise;
}
}
I have a byte[] where the first two bytes are a ushort which presents an ID that tells me what kind of data the rest of the array contains. Based on this ID I need to create a struct with its proper type to fill in the received data.
For now I thought that I maybe could use Dictionary, fill it on startup and afterwards get the proper type through it, but this includes lots of reflection and boxing as I get many byte[] to process.
Is there any possible solution without boxing and reflection to create the needed structtype based on the ushort ID?
EDIT:
public struct TestMessage
{
public const ushort typeCode = (ushort)Enums.MessageOpcodes.TestMessage;
public uint testuInt { internal set; get; }
public ushort testuShort { internal set; get; }
public ulong testuLong { internal set; get; }
public TestMessage(uint uInt, ushort uShort, ulong uLong)
{
testuInt = uInt;
testuShort = uShort;
testuLong = uLong;
}
}
public static ReadOnlyDictionary<ushort, object> messageTypes;
private static void PopulateMessageDict()
{
var tempMessageTypes = new Dictionary<ushort, object>();
tempMessageTypes.TryAdd(TestMessage.typeCode, new TestMessage());
messageTypes = new ReadOnlyDictionary<ushort, object>(tempMessageTypes);
}
public void TryAdd(this Dictionary<ushort, object> dictionary, ushort key, object value)
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, value);
}
else
{
Debug.Log("Key already exists in dictionary.");
}
}
So, based on your comments, I don't think you need the dictionary at all.
You said you want to take some bytes, look at the the first 2 to determine the message type, then deserialize into a message of the correct type and then process it in a way specific to that type.
So at a very high level, what you want is:
var opCode = (Enums.MessageOpcodes)(data[0] << 8 | data[1]);
switch (opCode)
{
case Enums.MessageOpcodes.TestMessage:
ProcessTestMessage(data);
break;
case Enums.MessageOpcodes.VectorMessage:
ProcessVectorMessage(data);
break;
}
Then your ProcessTestMessage method deserializes into a TestMessage struct and then processes it; likewise your ProcessVectorMessage and the VectorMessage struct.
You can generalize this a bit:
interface IMessageProcessor
{
Enums.MessageOpcodes Opcode { get; }
void DeserializeAndProcess(byte[] data);
}
Then:
class TestMessageProcessor : IMessageProcessor
{
public Enums.MessageOpcodes Opcode => Enums.MessageOpcodes.TestMessage;
public void DeserializeAndProcess(byte[] data)
{
// Deserialize into a TestMessage
// Process
}
}
Then you have your Dictionary<Enums.MessageOpcodes, IMessageProcessor> (or at this point, since the key is a property on the IMessageProcessor you can use a KeyedCollection):
class MessageProcessorLookup : KeyedCollection<Enums.MessageOpcodes, IMessageProcessor>
{
public override Enums.MessageOpcodes GetKeyForItem(IMessageProcessor item) => item.Opcode;
}
Then:
var lookup = new MessageProcessorLookup() { new TestMessageProcessor(), .... };
...
lookup[opcode].DeserializeAndProcess(data);
Ultimately, if you have a bunch of different structs, and you don't want to box them, you cannot have code which says "deserialize this data into an appropriate struct -- I don't care what sort -- then give it back to me", as you are going to have to box the struct to give it back. Likewise you can't say "deserialize this data into an appropriate struct and then push it onto this ConcurrentQueue which handles all message types" without boxing. All processing has to be "forward-only", with the method which deserializes into the struct calling onwards into the method which processes it.
Consider the flowing code snippet
static void Main()
{
var x = new MyStruct
{
Item = new StringWrapper("abc")
};
Console.WriteLine(x.Item.PublicField);
x.Item.SetValue("xyz");
Console.WriteLine(x.Item.PublicField);
var y = new
{
Item = new StringWrapper("abc")
};
Console.WriteLine(y.Item.PublicField);
y.Item.SetValue("xyz");
Console.WriteLine(y.Item.PublicField);
}
public struct MyStruct
{
public StringWrapper Item;
}
public struct StringWrapper
{
public string PublicField;
public StringWrapper(string v)
{
PublicField = v;
}
public void SetValue(string v)
{
PublicField = v;
}
}
And the output:
abc
xyz
abc
abc
MyStruct can be declared as class, and the output will remain the same.
{abc, abc} part of output is a surprise for me, as I expect anonymous type to be converted to class or struct and behave the same.
I feel like I'm missing something obvious here and will appreciate any help.
Thanks.
The difference here is that your MyStruct (struct or class) exposes a public field while anonymous classes (new { }) expose public properties.
When you access a value type from a field or variable, you do not get a copy, you access the instance directly. Therefore making changes to it stores them in the instance.
When you instead access it via a property or method, you get a returned copy of your StringWrapper and changing that doesn't change what is stored in the anonymous classes private field.
Just to demonstrate, you can get the same behavior by making your Item field a property too:
public StringWrapper Item { get; set; }
I have a struct on the server-side with a layout like this:
struct SomeStruct
{
public string SomeString { get; set; };
public string SomeString1;
public string SomeString2;
public string SomeString3;
}
I am using a client/server model, and an instance of this struct gets referenced a lot of times as it has really important information (over 200 times).
The thing is that when some function gets called, the values inside this struct become null. I don't know why and it is been bugging me for a really long time.
I call a lot of methods before realizing that this values are null, so I don't know which section of my code nullify my strings.
I am using VS2012, but I have 2010 and 2008 ultimate as well. I was wondering if there is a way to perform a trigger when some section of code nullifies my strings.
I tried to add some properties like this, bot the exception was never thrown:
struct SomeStruct {
string somestr;
public string SomeString
{
get { return somestr; }
set
{
if (value == null)
{
throw new Exception("stirng is null");
}
somestr = value;
}
}
public string SomeString1;
public string SomeString2;
public string SomeString3;
}
Might not be important, but this is one of the structs I am using (the Name variable becomes null in some part of my code, and the rest turns into default()):
[ProtoContract]
public struct CharacterInformation
{
[ProtoMember(2)]
public string Name;
[ProtoMember(3)]
public IntegerVector2 Position;
[ProtoMember(5)]
public CharacterDirection Direction;
[ProtoMember(6)]
public CharacterStatus Status;
[ProtoMember(7)]
public CharacterClass Class;
[ProtoMember(8)]
public CharacterRace Race;
[ProtoMember(9)]
public CharacterType Type;
[ProtoMember(10)]
public CharacterFaction Faction;
[ProtoMember(11)]
public float MovementModifier;
[ProtoMember(12)]
public CharacterEquipment Equipment;
}
Edit: The only instance of this struct is created on a Sql-related function:
public CharacterServerInformation GetInformation(int charID)
{
CharacterServerInformation information = new CharacterServerInformation();
if (!authInstance.CharacterExists(charID))
{
// char doesn't exists
throw new Exception("Character doesn't exists");
}
information.ID = charID;
information.Experience = GetExperience(charID);
information.Info.Direction = CharacterDirection.Bottom;
information.Info.Name = authInstance.CharacterGetName(charID);
information.Info.Class = GetClass(charID);
information.Info.Faction = GetFaction(charID);
information.Info.Position = GetPosition(charID);
information.Info.Race = GetRace(charID);
information.Info.Status = GetStatus(charID);
information.Info.Type = GetType(charID);
information.Info.MovementModifier = 1f; // should store old movement modifier, but well, whatever
information.HealthLeft = GetHealthLastLogout(charID);
return information;
}
I suspect the problem is purely because you're using struct and not making a class. Since struct members are copied by value into methods and when returned from methods, including property getters, it's likely that you're "losing" the information by accidentally writing a new struct somewhere.
In this case, class seems is far more appropriate. If you read Choosing Between Classes and Structures, you'll see that struct should only be used when:
It logically represents a single value, similar to primitive types (integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
In your case, all of these criteria ( except maybe the last) are being violated, so class would be more appropriate.
I'm teaching myself C#, so forgive me if this seems slightly obvious.
I'm trying to write a generic function that I can pass an array of structs into and then use one of the attributes of the struct. I have no idea how to declare a generic datatype in a function in a way that I can refer to attributes in the way needed.
Maybe what I'm asking can be better communicated in code - this is a non-working function to illustrate what I'm trying to do, how it strikes me as logical that it should work without actually knowing how to write it:
public static int AFunctionIsThis<DataType, int DataType.Value>(DataType passedrecord)
{
temp = passedrecord.Value * 2 + 1;
return temp;
}
And I want to be able to call it normally while specifying the attribute of the struct to be passed.
int NewVariable = AFunctionIsThis<ThisIsAStruct, ThisIsAStruct.AnIntAttribute>(ThisIsADeclaredStruct);
Thankyou very much,
Hanii Puppy.
You can't specify members that a generic type should contain, you can only specify the generic data type.
You would use an interface where the property is defined:
public interface IHaveValue {
int Value { get; }
}
Your struct would then implement the interface, and you can specify the interface as the generic data type:
public static int AFunctionIsThis<T>(T passedrecord) where T : IHaveValue {
return passedrecord.Value * 2 + 1;
}
However, with what you are using it for, you don't need to use generics at all, you can just use the interface:
public static int AFunctionIsThis(IHaveValue passedrecord) {
return passedrecord.Value * 2 + 1;
}
Note that you should most likely not use a struct at all, but a class. A struct is more complicated to implement correctly, so you should stick to classes until you have a really good reason to use a struct.
(To start with, note that the word "attribute" has a different meaning in .NET from the OOP sense.)
Use a Converter<T,int> and Action<T,int> delegate to get and set the member, respectively.
e.g.
public static int AFunctionIsThis<DataType>(DataType passedrecord, Converter<DataType,int> getter)
{
temp = getter(passedrecord) * 2 + 1;
return temp;
}
and then call it
AFunctionIsThis(ThisIsADeclaredStruct, x => x.AnIntProperty);
If you also need to set the value, you can use
AFunctionIsThis(ThisIsADeclaredStruct, x => x.AnIntProperty, (x, v) => { x.AnIntProperty = v; });
or do some magic with Expression<Converter<T>> to yank out the member reference and create a matching setter.
Hanii Puppy:
In short, yes, you should be able to do what you are doing, but here is a syntax that works:
public static int AFunctionIsThis<T>(T passedRecord) where T : DataType
{
var temp = passedRecord.Value;
return temp;
}
public class DataType
{
public int Value { get; set; }
}
Hope that helps.
Dave
What you want to do, is define a generic method that accepts only T that implements a certain interface or is derived from certain base class that has an int member called Value.
e.g:
public interface IClass { int Value{get;set;} }
public class ExampleImpl : IClass
{
int Value{get;set;}
/* Additional Members\methods here */
}
public class HelperClass
{
public static int GenMethod<T>(T item) where T:IClass
{
return item.Value * 2 + 1;
}
}