I have the following models
public class CustomEvent
{
private string _tag;
public int Id { get; set; }
public int PId { get; set; }
public DateTimeOffset TimeStamp { get; set; }
public string Mentor { get; set; }
public string Type { get; set; }
public string Tag
{
get => _tag;
set
{
_tag = GetTagTypeList.GetTagType(typeof(TagType)).Contains(value) ? value : "Unspecified";
}
}
}
public static class TagType
{
public const string Unspecified = "Unspecified";
public const string AmxPersonalItemCreate = "Amx.PersonalItem.Create";
public const string AmxPersonalItemUpdate = "Amx.PersonalItem.Update";
public const string AmxPersonalItemDelete = "Amx.PersonalItem.Delete";
public const string AmxRegionCreate = "Amx.Region.Create";
public const string AmxRegionUpdate = "Amx.Region.Delete";
public const string AmxRegionDelete = "Amx.Region.Update";
}
public class GetTagTypeList
{
public static List<String> GetTagType(Type type)
{
return type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Select(x=>x.GetValue(null).ToString()).ToList();
}
}
The above code restricts the setter to the list of static values. However this is very inefficient, as it is reflecting over the class every single time the method [GetTagType] is called.
I now have a requirement to Create a TagType class with a private constructor, and static values.
Given the values to be expressed have "." in them, it will require a custom json serializer as well.
I have read somewhere that a solution could be to use nested classes to get values which match the string being created.
i.e. for "Amx.PersonalItem.Create" we could create a class which resemble:
public static class Amx
{
public static class PersonalItem
{
public static TagType Create { get; } = new TagType("Amx.PersonalItem.Create");
}
}
I need to integrate the above example into my CustomEvent Class.
Or any other solution that uses static values to achieve same result.
Would appreciate any help ?
How about making a static item in the class that builds the list and stores it in a static variable? That means you can build the list once no matter how many times your setter is called. You still have to search the list but you don't need to use reflection.
Related
I have a situation where I need to get the value on a property on an attribute (decorator) applied to a class. That class that is decorated, is inheriting from an abstract class. It is this abstract class that needs to get the attribute information, but it needs to do so inside a static function.
I cannot post the exact scenario, but here is a terrible example that could do without attributes, but please work with it as it is:
public class VehicleShapeAttribute : Attribute
{
public string Shape { get; }
public VehicleShapeAttribute(string shape)
{
Shape = shape;
}
}
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public static string GetVehicleShape()
{
//return value from the attribute, from this static function. CANT DO THIS HERE
return AnyInheritingClass.VehicleShapeAttribute.Shape;
}
}
[VehicleShape("sedan")]
public class VauxhaulAstraSedan : Vehicle
{
//calling GetVehicleShape() on this class should automatically return "sedan"
}
Is this possible?
This is a bad example but I cannot post the actual code
Make the method non-static and resolve the runtime type with this.GetType():
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public string GetVehicleShape()
{
var attribute = Attribute.GetCustomAttribute(this.GetType(), typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
}
For a static version, you'll need to accept a Vehicle parameter whose type you can then inspect:
public static string GetVehicleShape(Vehicle vehicle)
{
var attribute = Attribute.GetCustomAttribute(vehicle.GetType());
// ...
Alternatively (and I'm just copy/pasting Mathias' code into another form syntactically here) if you really need to have the method static because you don't want to create an instance, you can add the following method to your attribute code (or any other static class, but I like to put it there with the attribute):
public static string GetFrom<T>()
{
return GetFrom(typeof(T));
}
public static string GetFrom(Type t)
{
var attribute = Attribute.GetCustomAttribute(t, typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
Then you could write code like:
var shape = VehicleShapeAttribute.GetFrom<VauxhaulAstraSedan>();
or
var shape = VehicleShapeAttribute.GetFrom(typeof(VauxhaulAstraSedan));
or even
var vehicle = new VauxhaulAstraSedan();
var shape = VehicleShapeAttribute.GetFrom(vehicle.GetType());
I am trying to automate the display (gathering via reflection) of my variables which are located in specific scripts in Unity. The trouble is assigning custom values (for example: "string DisplayName", "bool DisplayMe", "bool WriteMe" etc.). When it comes to my custom classes I understand how I would do it, but I would like to avoid remaking types like float, string, int etc. for this purpose.
For example, let's say I have:
public class myBaseClass
{
public string Name = "Display Name";
public bool AmReadable = true;
public bool AmWritable = true;
}
Then:
public class myDoubleFloat: myBaseClass
{
public float ValueFirst;
public float ValueSecond;
}
So in some scripts in Unity I define it:
public class SomeScriptOnGameObject : MonoBehaviour
{
public myDoubleFloat myFirstVariable{get; set;}
public float mySecondVariable{get; set;}
}
So later on with reflection I can check whether "myFirstVariable" should be read, it's display name etc. - while for "mySecondVariable" I cannot perform this check. How do I go about this without reinventing the wheel and making a class for each of these types like float, string, int, List etc.?
You can define a generic wrapper:
public class MyProperty<T>
{
private T _value;
public T Get() => _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
}
And make your properties's getters and setter to map to some backing fields of type MyProperty<T>:
public class SomeScriptOnGameObject : MonoBehaviour
{
private MyProperty<MyDoubleFloat> _myFirstVariable;
private MyProperty<float> _mySecondVariable;
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable.Get();
set => _myFirstVariable.Set(value);
}
public float MySecondVariable
{
get => _mySecondVariable.Get();
set => _mySecondVariable.Set(value);
}
public SomeScriptOnGameObject()
{
_myFirstVariable = new MyProperty<MyDoubleFloat>
{
//configuration
};
_mySecondVariable = new MyProperty<float>
{
//configuration
};
}
}
If you want to be fancy you can even add an implicit operator to get rid of Get() and make any T assignable from MyProperty<T>:
public class MyProperty<T>
{
private T _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
public static implicit operator T(MyProperty<T> myProperty) =>
myProperty != null ? myProperty._value : default;
}
And:
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable;
set => _myFirstVariable.Set(value);
}
Wrapping value objects (int, float, etc.) is probably not the best approach. Besides the additional complexity (and possibility for bugs), you are now bloating the memory footprint of your game.
(I'm intentionally avoiding newer C# syntax in these examples)
Since you are already in a reflection context, instead of wrapping your value objects, I'd suggest an attribute-based approach. For example:
public class SomeScriptOnGameObject
{
[DisplayName("First Variable"), Writable]
public float FirstVariable { get; set; }
[DisplayName("Second Variable")]
public float SecondVariable { get; set; }
[DisplayName("Some Field")]
public float Field;
public float FieldWithNoAttributes;
}
This has the advantage of keeping the metadata of the fields in the metadata, instead of carrying around a copy of everything with every instance you create.
The actual attributes are easy to create, also. I'll start with the simplest one, WritableAttribute:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class WritableAttribute : Attribute
{
}
This empty class is all that's needed to mark a field or property as "Writable". The AttributeUsage marks this as only valid on fields and properties (not, for example, a class).
The other attribute, DisplayName, is only slightly more complex:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class DisplayNameAttribute : Attribute
{
public string DisplayName { get; private set; }
public DisplayNameAttribute(string displayName)
{
DisplayName = displayName;
}
}
The main difference is the constructor with the displayName argument, and the DisplayName property. This forces the compiler to expect an argument to the attribute.
With some extension methods, you can make things very clean:
public static class AttributeExtensions
{
public static bool IsWritable(this MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(WritableAttribute)).Any();
}
public static string DisplayName(this MemberInfo memberInfo)
{
var displayNameAttribute =
memberInfo.GetCustomAttributes(typeof(DisplayNameAttribute))
.FirstOrDefault() as DisplayNameAttribute;
return displayNameAttribute == null ? null : displayNameAttribute.DisplayName;
}
public static PropertyInfo Property<T>(this T _, string propertyName)
{
return typeof(T).GetProperty(propertyName);
}
public static FieldInfo Field<T>(this T _, string fieldName)
{
return typeof(T).GetField(fieldName);
}
}
(Since you mentioned you are already using reflection, you might not need the last two methods there.)
Finally, a simple XUnit test to demonstrate:
public class UnitTest1
{
[Fact]
public void Test1()
{
var obj = new SomeScriptOnGameObject();
Assert.True(obj.Property("FirstVariable").IsWritable());
Assert.False(obj.Property("SecondVariable").IsWritable());
Assert.False(obj.Field("Field").IsWritable());
Assert.Equal("First Variable", obj.Property("FirstVariable").DisplayName());
Assert.Equal("Second Variable", obj.Property("SecondVariable").DisplayName());
Assert.Equal("Some Field", obj.Field("Field").DisplayName());
Assert.Null(obj.Field("FieldWithNoAttributes").DisplayName());
}
}
I have a method as follows which gets data and stores them to specific variables. I also have two static variables that preserves their value if a condition is met. My question is how can I store this data in attributes in a specific class ?
Like for example, I have a class called UserDetails with attributes :
UserDetails class
public class UserDetails {
public static string RateCountry { get; set; }
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Second Class
For now, its working like this. But I want to enhance it by making use of objects.
public static string RateCountry { get; private set; }
public static string RateWeek { get; private set; }
public ActionResult ShowList()
{
int start = Convert.ToInt32(Request["start"]);
int length = Convert.ToInt32(Request["length"]);
string name = Request["search[value]"];
string address = Request[("columns[3][search][value]")];
string rateType = Request[("columns[7][search][value]")];
if (string.IsNullOrEmpty(rateType)) // if null, reset the static variables to null
{
RateCountry = "";
RateWeek = "";
}
else
{
if (CheckDate(rateType)) // if contains date, assign to RateWeek
{
RateWeek = rateType;
}
else
{
RateCountry = rateType; // else if contains a string word, assing to ratecountry
}
}
var items = AssignDetails(start, length, name, address, RateWeek, RateCountry);
return items;
}
Then instead of passing several parameters like start, length, name etc. in the method AssignDetails, I can pass an object of the UserDetails class directly taking into consideration the static variables.
Can someone please help ?
Note: In C#, they are called properties not attributes. Attributes are a totally different thing.
What you want to do is straight forward:
Firstly, you need to change your method so it accepts your class UserDetails as an argument:
public void AssignDetails(UserDetails userDetails)
{
// Use userDetails here to do whatever you want
}
Secondly, when you call the above method, you need to pass the argument to it. You can create an instance of UserDetails and pass it to the AssignDetails method:
var userDetails = new UserDetails
{
Start = start,
Length = length,
Name = name
Address = address
}
I am not sure why RateWeek, and RateCountry properties are static in your class, but to set those you can do them as below (Please note it is using the class and not the instance of the class):
UserDetails.RateWeek = RateWeek;
You could make use of the instance's properties as an indirection to the class' static properties, although all this thing is really ugly in terms of design.
public class UserDetails
{
public static string PersistedRateCountry { get; set; }
public static string PersistedRateWeek { get; set; }
public static string RateCountry
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateCountry; }
set { PersistedRateCountry = value; }
}
public static string RateWeek
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateWeek; }
set { PersistedRateWeek= value; }
}
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
I strongly suggest you to move these static properties out to another class, which would be responsible for persisting them.
E.g. try to separate your Data Object (which just holds data) from your Business Object (which contains business logic, and is constructed by receiving a Data Object as parameter). Put all that crazy persistence logic in the Business Object, and use the Business Object everywhere in your code (instead of using the Data Object).
Keep your classes short and clean. If you are coding a lot in the same class, it's probably because you got a bad object-oriented design.
i have 6 structs for the player and also for the 5 bots. Everyone of them have some different variables and some that are equal to the other ones.I declare them like this
public struct Player
{
public static int Chips;
public static int Type;
public static int Power;
public static bool bot1Turn;
public static bool bot1FoldTurn;
public static AnchorStyles playerCardsAnchor = AnchorStyles.Bottom;
}
public struct Bot1
{
public static int bot1Chips;
public static int bot1Type;
public static int bot1Power;
public static bool bot1Turn;
public static bool bot1FoldTurn;
public static AnchorStyles bot1CardsAnchor = AnchorStyles.Left;
}
public struct Bot2
{
public static int bot2Chips;
public static int bot2Type;
public static int bot2Power;
public static bool bot2Turn;
public static bool bot2FoldTurn;
public static AnchorStyles bot2CardsAnchor = AnchorStyles.Right;
}
public struct Bot3
{
public static int bot3Chips;
public static int bot3Type;
public static int bot3Power;
public static bool bot3Turn;
public static bool bot3FoldTurn;
public static AnchorStyles bot3CardsAnchor = AnchorStyles.Top;
}
public struct Bot4
{
public static int bot4Chips;
public static int bot4Type;
public static int bot4Power;
public static bool bot4Turn;
public static bool bot4FoldTurn;
public static AnchorStyles bot4CardsAnchor = AnchorStyles.Bottom | AnchorStyles.Right;
}
public struct Bot5
{
public static int bot5Chips;
public static int bot5Type;
public static int bot5Power;
public static bool bot5Turn;
public static bool bot5FoldTurn;
public static AnchorStyles bot5CardsAnchor = AnchorStyles.Top | AnchorStyles.Left;
}
Later on i add the values in a static constructor :
static MainPoker()
{
Player.Chips = 100000;
Player.Power = 0;
Player.Type = -1;
Player.playerTurn = true;
Player.playerFoldTurn = false;
}
Now should i keep all the 6 structs like this, or there's some other way to put them all together ? I'm looking for something like interface but it should also be able to hold static variables .. Any suggestions ?
Structs are value types, while classes are reference types. You almost certainly want to use classes for this type of thing.
You have many properties (which you have implemented as fields) in common between players and bots, and between the different "bot numbers". You decided to give all of those properties different names, which makes it difficult to simplify the code.
Your fields are declared static. I would suggest making them instance fields (or probably instance properties).
If you make those changes, you can use inheritance to put similar things in a common base type
public class Agent
{
public int Chips;
public int Type;
public int Power;
public bool Turn;
public bool FoldTurn;
public AnchorStyles CardsAnchor;
}
public class Player : Agent
{
public Player() { CardsAnchor = AnchorStyles.Bottom; }
// Anything that makes a player different here
}
public class Bot : Agent
{
// Anything that makes a bot different here
public Bot(AnchorStyles style)
{
CardsAnchor = style;
}
}
Player player = new Player();
Bot bot1 = new Bot(AnchorStyles.Left);
Bot bot2 = new Bot(AnchorStyles.Right);
You an use properties in your code rather than fields. They will seem to behave similarly in code consuming the class, but properties afford more flexibility because they provide a layer between the value of something and how it is stored behind the scenes (for example, a property can be calculated based on the value of other properties or multiple backing fields). Using properties, you would instead write
public class Agent
{
public int Chips { get; set; }
public int Type { get; set; }
public int Power { get; set; }
public bool Turn { get; set; }
public bool FoldTurn { get; set; }
public AnchorStyles CardsAnchor { get; set; }
}
You don't want structs, you want classes (except you really want structs, but then you would know it)
and you are mixing classes with instances of classes (objects).
Generate just one Player class and then create instances from it:
public class Player
{
public int Chips { get; set; }
public int Type { get; set; }
public int Power { get; set; }
public bool BotTurn { get; set; }
public bool BotFoldTurn { get; set; }
public AnchorStyles PlayerCardsAnchor { get; }
public Player(AnchorStyles playerCardsAnchor, more parameters for properties)
{
PlayerCardsAnchor = playerCardsAnchor;
// set other properties here
}
}
MainPoker()
{
var player = new Player(AnchorStyles.Bottom, more parameters);
var bot1 = new Player(AnchorStyles.Left, more parameters);
//more bots
}
If you need a static way to acces these, create a static class that holds references to these instances.
public static class PokerTable
{
public static Player Player { get; }
public static Player Bot1 { get; }
// more bots
static PokerTable()
{
Player = new Player(AnchorStyles.Bottom, more parameters);
Bot1 = new Player(AnchorStyles.Left, more parameters);
//more bots
}
}
Then you can access the instances in a static way using
PokerTable.Player.Chips = 10;
This is the first time that I'm doing this, so I need a little bit of help,
I have this code behind:
List<Trucks> FinalListOfTrucks = new List<Trucks>();
public class Trucks
{
public string Placa;
public string Lock;
public string Event;
public DateTime Date;
public string TipoCamion;
public string Person;
public string MissedDate;
}
protected void btnProcess_Click(object sender, EventArgs e)
{
Trucks item = new Trucks();
item.Placa = "MA2323";
item.Lock = "lock1";
item.Event = "Event1";
item.Date = DateTime.Now;
item.TipoCamion = "TRUCK1";
item.Person = "JULIAN";
item.MissedDate = "";
FinalListOfTrucks.Add(item);
gvOriginal.DataSource = FinalListOfTrucks;
gvOriginal.DataBind();
}
in design:
<asp:Button ID="btnProcess" runat="server" Text="Process"
onclick="btnProcess_Click" />
<asp:GridView ID="gvOriginal" runat="server"></asp:GridView>
But trying to run the web app, I'm getting the following error:
The data source for GridView with id 'gvOriginal' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.
Do I have to do anything else, to make this work?
Databinding relies on using properties rather than fields, as the error message you got indicates. You can easily change your code so that Trucks uses properties instead:
public class Trucks
{
public string Placa { get; set; }
public string Lock { get; set; }
public string Event { get; set; }
public DateTime Date { get; set; }
public string TipoCamion { get; set; }
public string Person { get; set; }
public string MissedDate { get; set; }
}
If you make that change everything should work.
Note that there are a number of subtle differences between properties and public fields. A property is effectively syntactic sugar around methods, so public string Placa {get;set;} would be transformed into something similar to:
private string _placa;
public string GetPlaca() { return _placa; }
public void SetPlaca(string value) { _placa = value; }
As for the differences between methods and fields, that's probably beyond the scope of this question.
You can bind to lists gridviews, but your class has to use PROPERTIES, not variables.
public class Trucks
{
public string Placa{get;set;}
public string Lock{get;set;}
public string Event{get;set;}
public DateTime Date{get;set;}
public string TipoCamion{get;set;}
public string Person{get;set;}
public string MissedDate{get;set;}
}