I am writing a class which holds 90 integer variables. There are basically 10, but each has 3x3 attributes, making them 90. I'll explain it further.
So the 10 variables I have are: v0, v1, v2, ..., v9. Each of these has three different values, for city, county and state. Also, each of these has three different values for past, present and future.
So, a typical value would be: v3.City.Future or v7.State.Past or v8.County.Present.
I was thinking to implement a class, with 10 structs for each variable, then each of those struct has a three nested structs (for city, county and state) and each of those structs has three integer variables for past, present and future.
This is still in the conceptual phase. I tried to go with the above mentioned approach, but it is not working.
Here is the code snippet:
public class MyClass
{
public MyVariable myvariable;
}
public struct MyVariable
{
public struct National
{
public int Past { get; set; }
public int Present { get; set; }
public int Future { get; set; }
}
...
}
Now when I instantiate the class and access the member (myclass.myvariable.National.Past), it does not get the member.
Here is the answer to this:
public struct PeriodVars
{
public int Past { get; set; }
public int Present { get; set; }
public int Future { get; set; }
}
public struct VarStruct
{
public PeriodVars City;
public PeriodVars County;
public PeriodVars State;
}
Now the class will be:
public class MyClass
{
public VarStruct v0;
public VarStruct v1;
...
}
Once I instantiate an object of the class, I can refer it to like this:
objMyClass.v0.City.Past = 111;
Based on your comment, it looks like you are mixing types and instances:
Assuming your MyVariable looks like the following:
public struct MyVariable
{
public struct National
{
public int Past;
}
public National ValueForNational;
}
myclass.myvariable.National - it is a type (will not compile)
myclass.myvariable.National.Past - it is a member of a type (will not compile)
myclass.myvariable.ValueForNational - is value for a member of MyVariable member inside MyClass' variable (would compile)
myclass.myvariable.ValueForNational.Past - is one that you probably want...
Here is a simple set of classes to accomplish that. I used classes instead of structs as there are some "gotchas" you will need to understand if you use structs.
Unless maybe if you describe "it is not working", I bet that your problem actually is that you are trying to use structs.
public class Foo<T>
{
public T Future;
public T Present;
public T Past;
}
public class Bar
{
public Foo<string> City;
public Foo<string> State;
public Foo<string> Country;
}
public class Top
{
public Bar v0;
public Bar v1;
//...
public Bar v2;
}
There is an initialization missing under struct MyVaribale.
public National national;
internal class Program
{
static void Main(string[] args)
{
var myVar = new MyClass();
myVar.myvariable.national.Past = 1;
}
}
public class MyClass
{
public MyVariable myvariable;
}
public struct MyVariable
{
public National national; // This line is missing. That's why you can't access the members of the 'National' struct.
public struct National
{
public int Past;
public int Present;
public int Future;
}
}
Related
When using the C# with keyword with an actual struct type it works exactly as expected, however when dealing with some generic type T that is constrained to be a struct it results in a compiler error.
Is this a bug or intended behaviour, and if so, what's stopping the generic approach from working?
public interface ICountSomething
{
public int Counter { get; }
}
public struct ActualStruct : ICountSomething
{
public string Name { get; init; }
public int Counter { get; init; }
}
public class Blah<T>
where T : struct, ICountSomething
{
public T DoSomethingWithGenericConstrainedToStruct(T input)
{
// Does not compile
return input with
{
Counter = input.Counter + 1,
};
}
public ActualStruct DoSomethingWithActualStruct(ActualStruct input)
{
// Compiles ok
return input with
{
Counter = input.Counter + 1,
};
}
}
There are two issues - Counter on the interface is readonly so it can't be modified and/or used inside with expression. Change the interface to:
public interface ICountSomething
{
public int Counter { get; init; }
}
The with itself seems to be Rider/Resharper issue, the code should compile just fine (after adding init to the interface) - checked at sharplab.io. Submitted the bug for Rider.
Since T is a generic type, the compiler does not know which type is going to be used for T.
It knows it is a struct, but it cannot tell which properties struct T has.
The with keyword has to know which properties it can set. Since there is no way the compiler can possibly know which properties there are in T, you cannot use with.
Edit: this works: notice the init on the property of the interface.
public interface ICountSomething
{
public int Counter { get; init; }
}
public struct ActualStruct : ICountSomething
{
public string Name { get; init; }
public int Counter { get; init; }
}
public class Blah<T>
where T : struct, ICountSomething
{
public T DoSomethingWithGenericConstrainedToStruct(T input)
{
// Compiles ok
return input with
{
Counter = input.Counter + 1,
};
}
public ActualStruct DoSomethingWithActualStruct(ActualStruct input)
{
// Compiles ok
return input with
{
Counter = input.Counter + 1,
};
}
}
I have created a user control that contains an ObservableCollection<Something>. I learned that I cannot cast say ObservableCollection<Tiger> to ObservableCollection<Animal>. The solution I found was to add a helper class that handles all low level collection manipulation. My suspicion is that there is a more elegant solution and if so, maybe someone can point me into that direction.
See the code below that captures the problem and my solution. Zoo corresponds to the WPF UserControl. (Actually a zoo for one type od animal.) Ideally I would define it as Zoo<T> i.e. as a generic type but that would prevent me from using XAML. I need to define Animals as object in order assign to it.
class Program
{
public static void Main(string[] args)
{
Zoo zoo = new Zoo();
List<Tiger> tigers = new List<Tiger>() { new Tiger() };
zoo.Animals = tigers;
zoo.Helper = new TigerHelper(tigers);
Console.WriteLine(zoo.GetCount());
Console.ReadLine();
}
}
public class Animal { }
public class Tiger : Animal { }
public interface Helper { int GetCount(); }
public class TigerHelper : Helper
{
private List<Tiger> tigers;
public TigerHelper(List<Tiger> tigers) { this.tigers = tigers; }
public int GetCount() { return tigers.Count; }
}
public class Zoo
{
public object Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Helper.GetCount(); }
}
Rather than go all the way down to object, you can use IList. This gives you access to most of the features of the list, but without the generics. For example, you can still access the Count property:
public class Zoo
{
public IList Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Animals.Count; }
}
Is it possible in C# to bind two objects of different classes but with similar properties?
For Example:
class Program
{
static void Main(string[] args)
{
test t = new test();
test2 t2 = new test2();
}
}
public class test
{
public int Number { get; set; }
}
public class test2
{
public int Number { get; set; }
}
So is it possible to say t = t2 somewhow?
You can have both classes implement an interface, if you don't care about what implementation of the interface is used.
For example:
class Program
{
static void Main(string[] args)
{
INumber t = new test();
INumber t2 = new test2();
}
}
public class test : INumber
{
public int Number { get; set; }
}
public class test2 : INumber
{
public int Number { get; set; }
}
public interface INumber
{
int Number { get; set; }
}
An interface is a sort of contract, that provides a definition of what properties and methods an implementing class must define. You can read more on interfaces here.
When your classes implement a shared interface, you're able to to implicitly convert one type into another type, such as in the example above.
Without the addition of extra code, no, you cannot do that.
Even though they are "similar" they are regarded as totally different types by the compiler, and cannot be assigned to each other.
Now, you can include an implicit operator on one (or both) in order to allow implicit casting between the two.
public class test
{
public static implicit operator test(test2 t)
{
return new test(tt.Number);
}
public static implicit operator test2(test t)
{
return new test2(t.Number);
}
public int Number { get; set; }
}
But that is as close as you can get to supporting that syntax.
I'm trying to determine how to address this use case using protobuf-net (Marc Gravell's implementation).
We have class A, which is considered version 1
An instance of class A has been serialized to disk
We now have class B, which is considered version 2 of class A (there were so many things wrong with class A, we had to create class B for the next version). Class A still exists in code, but only for legacy purposes.
I want to deserialize the version:1 data (stored to disk) as a class B instance, and use a logic routine to translate the data from the previous class A instance to a new instance of class B.
The instance of class B will be serialized to disk during operation.
The application should expect to deserialize instances of both class A and B.
The concept of data contract surrogates and the DataContractSerializer come to mind. The goal is transition the version:1 data to the new class B structure.
An example:
[DataContract]
public class A {
public A(){}
[DataMember]
public bool IsActive {get;set;]
[DataMember]
public int VersionNumber {
get { return 1; }
set { }
}
[DataMember]
public int TimeInSeconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject CustomObj {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
[DataContract]
public class B {
public B(A a) {
this.Enabled = a.IsActive; //Property now has a different name
this.TimeInMilliseconds = a.TimeInSeconds * 1000; //Property requires math for correctness
this.Name = a.Name;
this.CustomObject2 = new CustomObject2(a.CustomObj); //Reference objects change, too
this.ComplexThings = new List<ComplexThings>();
this.ComplexThings.AddRange(a.ComplexThings);
...
}
public B(){}
[DataMember]
public bool Enabled {get;set;]
[DataMember]
public int Version {
get { return 2; }
set { }
}
[DataMember]
public double TimeInMilliseconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject2 CustomObject {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
Class A was the first iteration of our object, and is actively in use. Data exists in v1 format, using class A for serialization.
After realizing the error of our ways, we create a new structure called class B. There are so many changes between A and B that we feel it's better to create B, as opposed to adapting the original class A.
But our application already exists and class A is being used to serialize data. We're ready to roll our changes out to the world, but we must first deserialize data created under version 1 (using class A) and instantiate it as class B. The data is significant enough that we can't just assume defaults in class B for missing data, but rather we must transition the data from a class A instance to class B. Once we have a class B instance, the application will serialize that data again in class B format (version 2).
We're assuming we'll make modifications to class B in the future, and we want to be able to iterate to a version 3, perhaps in a new class "C". We have two goals: address data already in existence, and prepare our objects for future migration.
The existing "transition" attributes (OnSerializing/OnSerialized,OnDeserializing/OnDeserialized,etc.) don't provide access to the previous data.
What is the expected practice when using protobuf-net in this scenario?
Right; looking at them you have indeed completely changed the contract. I know of no contract-based serializer that is going to love you for that, and protobuf-net is no different. If you already had a root node, you could do something like (in pseudo-code):
[Contract]
class Wrapper {
[Member] public A A {get;set;}
[Member] public B B {get;set;}
[Member] public C C {get;set;}
}
and just pick whichever of A/B/C is non-null, perhaps adding some conversion operators between them. However, if you just have a naked A in the old data, this gets hard. There are two approaches I can think of:
add lots of shim properties for compatibility; not very maintainable, and I don't recommend it
sniff the Version as an initial step, and tell the serializer what to expect.
For example, you could do:
int version = -1;
using(var reader = new ProtoReader(inputStream)) {
while(reader.ReadFieldHeader() > 0) {
const int VERSION_FIELD_NUMBER = /* todo */;
if(reader.FieldNumber == VERSION_FIELD_NUMBER) {
version = reader.ReadInt32();
// optional short-circuit; we're not expecting 2 Version numbers
break;
} else {
reader.SkipField();
}
}
}
inputStream.Position = 0; // rewind before deserializing
Now you can use the serializer, telling it what version it was serialized as; either via the generic Serializer.Deserialize<T> API, or via a Type instance from the two non-generic APIs (Serializer.NonGeneric.Deserialize or RuntimeTypeModel.Default.Deserialize - either way, you get to the same place; it is really a case of whether generic or non-generic is most convenient).
Then you would need some conversion code between A / B / C - either via your own custom operators / methods, or by something like auto-mapper.
If you don't want any ProtoReader code kicking around, you could also do:
[DataContract]
class VersionStub {
[DataMember(Order=VERSION_FIELD_NUMBER)]
public int Version {get;set;}
}
and run Deserialize<VersionStub>, which will give you access to the Version, which you can then use to do the type-specific deserialize; the main difference here is that the ProtoReader code allows you to short-circuit as soon as you have a version-number.
I don't have an expected practice, but this is what I'd do.
Given you still have access to your V1 class add a property on your V1 class that provides a V2 instance.
In your ProtoAfterDeserialization of V1 create an instance of V2 and seeing it's a Migration I'd suggest manually transfer across what you need (or if it's not too hard, try Merge YMMV).
Also in your ProtoBeforeSerialization throw some form of exception so that you don't attempt to write out the old one any more.
Edit: Examples of using these (VB code)
<ProtoBeforeSerialization()>
Private Sub BeforeSerialisaton()
End Sub
<ProtoAfterSerialization()>
Private Sub AfterSerialisaton()
End Sub
<ProtoBeforeDeserialization()>
Private Sub BeforeDeserialisation()
End Sub
<ProtoAfterDeserialization()>
Private Sub AfterDeserialisation()
End Sub
after seeing your example I hope this satisfied what you are trying to do. Class1 is how you load/convert.
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
public class Class1
{
public Class1()
{
using (FileStream fs = new FileStream("c:\\formatADataFile.dat",
FileMode.Open, FileAccess.Read))
{
A oldA = Serializer.Deserialize<A>(fs);
B newB = oldA.ConvertedToB;
}
}
}
[ProtoContract()]
public class B
{
public B(A a)
{
//Property now has a different name
this.Enabled = a.IsActive;
//Property requires math for correctness
this.TimeInMilliseconds = a.TimeInSeconds * 1000;
this.Name = a.Name;
//Reference objects change, too
this.CustomObject2 = new CustomObject2(a.CustomObj);
this.ComplexThings = new List<ComplexThings>();
this.ComplexThings.AddRange(a.ComplexThings);
//...
}
public B() { }
//[DataMember]
[ProtoMember(1)]
public bool Enabled { get; set; }
//[DataMember]
public int Version
{
get { return 2; }
private set { }
}
[ProtoMember(2)]
public double TimeInMilliseconds { get; set; }
[ProtoMember(3)]
public string Name { get; set; }
[ProtoMember(4)]
public CustomObject2 CustomObject { get; set; } //Also a DataContract
[ProtoMember(5)]
public List<ComplexThing> ComplexThings { get; set; } //Also a DataContract
///...
}
[ProtoContract()]
public class CustomObject2
{
public CustomObject2()
{
Something = string.Empty;
}
[ProtoMember(1)]
public string Something { get; set; }
}
[ProtoContract()]
public class A
{
public A()
{
mBConvert = new B();
}
[ProtoMember(1)]
public bool IsActive { get; set; }
[ProtoMember(2)]
public int VersionNumber
{
get { return 1; }
private set { }
}
[ProtoBeforeSerialization()]
private void NoMoreSavesForA()
{
throw new System.InvalidOperationException("Do Not Save A");
}
private B mBConvert;
[ProtoAfterDeserialization()]
private void TranslateToB()
{
mBConvert = new B(this);
}
public B ConvertedToB
{
get
{
return mBConvert;
}
}
[ProtoMember(3)]
public int TimeInSeconds { get; set; }
[ProtoMember(4)]
public string Name { get; set; }
[ProtoMember(5)]
public CustomObject CustomObj { get; set; } //Also a DataContract
[ProtoMember(6)]
public List<ComplexThing> ComplexThings { get; set; } //Also a DataContract
//...
}
[ProtoContract()]
public class CustomObject
{
public CustomObject()
{
}
[ProtoMember(1)]
public int Something { get; set; }
}
[ProtoContract()]
public class ComplexThing
{
public ComplexThing()
{
}
[ProtoMember(1)]
public int SomeOtherThing { get; set; }
}
I have some different objects that all of them have a integer field called Place. Is there a way to sort out this list without knowing what is the actual object? I mean just accessing the Place field and sort the list based on this number. possibly using linq or something?
some example objects:
public class Car
{
public int Place;
//Other related fields
}
public class Human
{
public int Place;
//Other related fields
}
//Somwhere in program
List<object> GameObjects;
You should derive your classes from a base class.
public class Base
{
public int Place;
}
public class Car : Base
{
// other properties
}
public class Human : Base
{
// other properties
}
Then you can create a list of your base type, add humans
and cars. After that you can use the Linq Sort or OrderBy method.
List<Base> list = new List<Base>();
list.Add(new Human { Place = 2 });
list.Add(new Car { Place = 1 });
var sortedList = list.Sort(x => x.Place);
More Information
The C# Station Tutorial - Lesson 8: Class Inheritance
MSDN - Queryable.OrderBy
MSDN - List.Sort Method
No because object doesn't have a Place property only Car/Human do.
There are a couple of ways you can solve this problem:
Introduce a base class
public class GameObject
{
public int Place { get; set; }
}
public class Car : GameObject
{}
public class Human : GameObject
{}
...
List<GameObject> GameObjects
Use a generic interface
public interface IGameObject
{
int Place { get; }
}
public class Car : IGameObject
{
public int Place { get; set; }
}
public class Human : IGameObject
{
public int Place { get; set; }
}
List<IGameObject> GameObjects
What you just discovered is relationship between those types. Both Car and Human seem to have a Place property, so you should extract an interface à la IGameObject.
The best way is to use an interface. If you can't, you still can do late binding using the dynamic keyword:
var list = new List<object>
{
new Car { Place = 3 },
new Human { Place = 1 },
new Car { Place = 2 }
};
var sortedList = list.OrderBy(o => ((dynamic)o).Place);
Yes, its possible using delegate methods with reflection. This is upto my knowledge, may be some other giants create it without using reflection
The best you can do is use an Interface, like this:
public Interface IFoo
{
int place;
}
And the implement that interface:
public class Car : IFoo
{
public int Place;
}
public class Human : IFoo
{
public int Place;
}
And then with linq:
List<IFoo> GameObjects;
GameObjects.OrderBy(g => g.Place);
You could let them implement an interface IPlaceable and use a property instead of only a field:
public interface IPlaceable
{
int Place { get; set; }
}
public class Car : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
public class Human : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
// Somwhere in program
List<IPlaceable> GameObjects;
// Somwhere else
GameObjects.OrderBy(go => go.Place);
Note that the list now is a List<IPlaceable> instead of a List<Object>.