Code snippet: create an "alias" for something else - c#

I was looking for a similar way to create an alias for something else like its possible in C using preprocessor (this question is a bit similar, couldn't find anything useful there).
This is the problem: I've got a method that receives an array, but each position of the array has a specific meaning, like they where different parameters with specific names. What I want to do is to make my code easier to read (and write) by using those specific names, but, on the other hand, I don't want to create another method call (like in example 1) nor assign the array positions to new variables (example 2), because the performance is critical.
Example 1:
void OriginalMethodSignature(Type[] values)
{
SimplifiedMethod(values[0], values[1], ... values[n]);
}
void SimplifiedMethod(Type specificName1, Type specificName2, ... Type specificNameN)
{
// simple implementation using specific names instead of values[n]
}
Example 2:
void OriginalMethodSignature(Type[] values)
{
Type specificName1 = values[0];
Type specificName2 = values[1];
...
Type specificNameN = values[n];
// simple implementation using specific names instead of values[n]
}
I cannot change the method signature because its used in a dellegate, the Type is fixed.
The next example is a bit better, but still not optimum:
void OriginalMethodSignature(Type[] values)
{
// implementation using values[specificName1] ... values [specificNameN]
}
const int specificName1 = 0;
const int specificName2 = 1;
...
const int specificNameN = n-1;
Is there any way to create an snippet for this purpose? If yes, how would it be?

There isn't any built in way to do what you wan't, because you shouldn't really be doing it at all. You should be using an object with properties instead of an array.
Anyway, you can make an object that encapsulates the array, so that the properties use the array as storage:
public class NamedObject {
private Type[] _values;
public NamedObject(Type[] values) {
_values = values;
}
public SpecificName1 { get { return _values[0]; } set { _values[0] = value; } }
public SpecificName2 { get { return _values[1]; } set { _values[1] = value; } }
public SpecificName3 { get { return _values[2]; } set { _values[2] = value; } }
public SpecificName4 { get { return _values[3]; } set { _values[3] = value; } }
public SpecificName5 { get { return _values[4]; } set { _values[4] = value; } }
public SpecificName6 { get { return _values[5]; } set { _values[5] = value; } }
}
Now you can use the object to access the array:
void OriginalMethodSignature(Type[] values) {
NamedObject obj = new NamedObject(values);
// get a value
Type x = obj.SpecificName4;
// set a value
obj.SpecificName2 = x;
}

Create a dedicated class or struct, and parse the array into it.
public class MyClassOfStuff
{
Type SpecificName1 {get;set;}
Type SpecificName2 {get;set;}
public static MyClassOfStuff Parse(Type[] value)
{
Type specificName1 = values[0];
Type specificName2 = values[1];
...
Type specificNameN = values[n];
}
}
void OriginalMethodSignature(Type[] values)
{
var mystuff = MyClassOfStuff.Parse(values);
}

Related

How to get a property value of a class defined inside of another class through a reflection

I have a MerchantWSBO and MerchantWSVO classes.
MerchantWSBO has a property of a type of MerchantWSVO.
I need to get a value of the property of a MerchantWSVO.
So, I have a code defining both classes(classes are coming through a WebReference from a 3rd party)
public MerchantWSBO {
private MerchantWSVO overviewField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public MerchantWSVO overview {
get {
return this.overviewField;
}
set {
this.overviewField = value;
}
}
}
public MerchantWSVO{
private System.Nullable<bool> discoverRetainedField;
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool discoverRetainedSpecified {
get {
return this.discoverRetainedFieldSpecified;
}
set {
this.discoverRetainedFieldSpecified = value;
}
}
}
I have the following method where I need to get the property value of dicoverRetained using reflection:
private string ClassToXML(Object classObject)
{
MerchantTest mt = new MerchantTest();
if(classObject is MerchantWSBO)
{
classObject.GetType().GetProperty("overviewField").GetValue(new MerchantWSVO, null);
mt.overview.discoverRetained = //need to get the value
}
var myString = new System.IO.StringWriter();
var serializer = new XmlSerializer(classObject.GetType());
serializer.Serialize(myString, classObject);
return myString.ToString();
}
Based on a parameter classObject which in this case can be of two types, I need to get a value from a property.
How can I do that?
You don't need reflection at all, simply cast the object to the correct type. Pattern matching helps here.
if(classObject is MerchantWSBO wsbo)
{
Console.WriteLine(wsbo.overview.discoverRetained);
}
or on older C# versions:
var wsbo = classObject as MerchantWSBO;
if(wsbo != null)
{
Console.WriteLine(wsbo.overview.discoverRetained);
}

Is there a way to iterate through list of generic values in Unity/c#?

Is it possible to iterate through a several generic instances and do something with them?
public class Dynamic<T>
{
public T value;
public T defaultVal;
public void SetDefaultValue()
{
value = defaultVal;
}
}
Is it even possible to make it look something like this:
List<Dynamic<T>> dynamics = new List<Dynamics<T>>();
dynamics.Add(new Dynamic<float>());
dynamics.Add(new Dynamic<Vector2>());
///...
foreach (var item in dynamics)
{
item.SetDefaultValue();
}
And yeah, its probably useless at all since I have to manually insert these values in that list, but I really want to know if its even possible.
With the data model you have, in c# 2.0 there is no way to do what you want other than by declaring dynamics as a List<object> and using reflection:
List<object> dynamics = new List<object>();
dynamics.Add(new Dynamic<float>());
dynamics.Add(new Dynamic<Vector2>());
foreach (var item in dynamics)
{
item.GetType().GetMethod("SetDefaultValue").Invoke(item, null);
}
Not really recommended, since the performance will be poor, and you lose compile-time checking for correctness.
Instead, consider introducing a non-generic interface that allows accessing required members of Dynamic<T> in a non-generic manner:
public interface IDynamic
{
// Provide read-only access to the Value and DefaultValue as objects:
object Value { get; }
object DefaultValue { get; }
// Set the value to the default value:
void SetDefaultValue();
}
public class Dynamic<T> : IDynamic
{
public T value;
public T defaultVal;
public void SetDefaultValue()
{
value = defaultVal;
}
// Use explicit interface implementation because we don't want people to use the non-generic properties when working directly with a specific Dynamic<T>:
object IDynamic.Value { get { return value; } } // Note that if T is a struct the value will get boxed
object IDynamic.DefaultValue { get { return defaultVal; } } // Note that if T is a struct the value will get boxed
}
Now you will be able to do:
List<IDynamic> dynamics = new List<IDynamic>();
dynamics.Add(new Dynamic<float>());
dynamics.Add(new Dynamic<Vector2>());
foreach (var item in dynamics)
{
item.SetDefaultValue();
}
Extending dbc's answer, to have the properties of your class stored in a list to change them at once and by reference you need to wrap them into a class, for this case Dynamic<whatever>, because if you have primitive/value types, those will be copied into the list, and even the property values are changed looping through the list you would be changing the list copies and not the class properties themselves. Like so:
using System;
using System.Collections.Generic;
using UnityEngine;
public class GenericTrial2 : MonoBehaviour {
Dynamic<float> vertical = new Dynamic<float> { value = 17, defaultVal = 1 };
Dynamic<Vector2> run = new Dynamic<Vector2> { value = new Vector2(17, 17), defaultVal = Vector2.one };
Dynamic<Quaternion> rotation= new Dynamic<Quaternion> { value = new Quaternion(4,4,4,4), defaultVal = Quaternion.identity };
List<IDynamic> dynamics;
private void Start() {
dynamics = new List<IDynamic>();
dynamics.Add(vertical);
dynamics.Add(run);
dynamics.Add(rotation);
dynamics.ForEach(prop => { Debug.Log(prop.Value.ToString()); });
Debug.Log($"initValues: vertical: {vertical.value.ToString()}, " +
$"run: {run.value.ToString()}, rot: {rotation.value.ToString()} ");
}
void resetProps() {
foreach (var item in dynamics) {
item.SetDefaultValue();
}
dynamics.ForEach(prop => { Debug.Log(prop.Value.ToString()); });
}
private void Update() {
if (Input.GetKeyDown(KeyCode.Space)) {
resetProps();
Debug.Log($"after reset: vertical: {vertical.value.ToString()}, " +
$"run: {run.value.ToString()}, rot: {rotation.value.ToString()} ");
}
}
}
public interface IDynamic {
// Provide read-only access to the Value and DefaultValue as objects:
object Value { get; }
object DefaultValue { get; }
// Set the value to the default value:
void SetDefaultValue();
}
public class Dynamic<T> : IDynamic {
public T value;
public T defaultVal;
public void SetDefaultValue() {
value = defaultVal;
}
// Use explicit interface implementation because we don't want people to use the non-generic properties when working directly with a specific Dynamic<T>:
object IDynamic.Value { get { return value; } } // Note that if T is a struct the value will get boxed
object IDynamic.DefaultValue { get { return defaultVal; } } // Note that if T is a struct the value will get boxed
}
Output:
initValues: vertical: 17, run: (17.0, 17.0), rot: (4.0, 4.0, 4.0, 4.0)
after reset: vertical: 1, run: (1.0, 1.0), rot: (0.0, 0.0, 0.0, 1.0)

Creating a Session Helper Class that uses an array object C#

I am using a session helper class to track more than several variable. So far I have 30 that are needed from page to page, not all at once of course. I need to convert some of the values from single to array. The Session helper class I use is as follows. For brevity I have shown only two session variables we use for tracking tab index for two accordions.
using System;
using System.Globalization;
using System.Linq;
using System.Web;
public class SessionHelper
{
//Session variable constants
public const string AccordionTop = "#tabTop";
public const string AccordionBot = "#tabBot";
public static T Read<T>(string variable)
{
object value = HttpContext.Current.Session[variable];
if (value == null)
return default(T);
else
return ((T)value);
}
public static void Write(string variable, object value)
{
HttpContext.Current.Session[variable] = value;
}
public static int TabTop
{
get
{
return Read<int>(AccordionTop);
}
set
{
Write(AccordionTop, value);
}
}
public static int TabBot
{
get
{
return Read<int>(AccordionBot);
}
set
{
Write(AccordionBot, value);
}
}
}
So on each page I can work with variables easily as follows:
To Write:
SessionHelper.TabTop = 1; or SessionHelper.TabBot = 3
To Read:
If (SessionHelper.TabTop……….)
This all works fine. I now want to extend this to array values held in session. The array contains int, string and date time value.
For the array session object I have tried adding:
public class SessionHelper
{
public const string CompInfo = "CompAccInfo";
public static T ReadArray<T>(string variable)
{
object[] result = HttpContext.Current.Session[variable] as object[];
if (result == null)
{
return default(T);
//result = new object[30];
}
else
return ((T)(object)result);
}
public static void WriteArray(string variable, object[] value)
{
HttpContext.Current.Session[variable] = value;
}
public static object[] CompDetails
{
get
{
return ReadArray<object[]>(CompInfo);
}
set
{
WriteArray(CompInfo, value);
}
}
}
But then I get an “Object reference not set to…… error when I try to do this:
public void EGetCompanyInformation(MasterPage myMaster, int entityCode)
{
int prevEntity = 0;Using (sqlconnetiooo
.....
//I get values here this works fine
//Then:
sqlr = cmd.ExecuteReader();
sqlr.Read();
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
//Company Name.
SessionHelper.CompDetails[1] = sqlr.GetString(1);
//Currency Unit.
SessionHelper.CompDetails[2] = sqlr.GetString(2);
//Base Currency Code.
SessionHelper.CompDetails[3] = sqlr.GetString(3);
//Reporting Currency Code.
SessionHelper.CompDetails[4] = sqlr.GetString(4);
//Company Year End.
SessionHelper.CompDetails[5] = yearEndDiff;
//Country Code.
SessionHelper.CompDetails[6] = sqlr.GetString(6);
//Country Name.
SessionHelper.CompDetails[7] = sqlr.GetString(7);
//Base Currency Name.
SessionHelper.CompDetails[8] = sqlr.GetString(8);
//Report Currency Name.
SessionHelper.CompDetails[9] = sqlr.GetString(9);
//ClientID.
SessionHelper.CompDetails[10] = sqlr.GetInt32(10);
Other code here
}
}
It seems any SessionHelper.CompDetails[i] does not work : Error Object reference not set to an instance of an object.
What will happen if ReadArray will return default(T)? It will return null. Than access to any object by index inside the array will cause the exception you face.
It is not quite obvious what your code is intended to do.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
What do you want here? CompDetails itself should return an array. But you are trying to rewrite it immediately by some values.
If you want to access the CompDetails and rewrite it's objects than you have to instantiate it by
int n = 10;
SessionHelper.CompDetails = new CompDetails[n];
default(object[]) will always throw null. because the array of object is reference type and default value of any reference type is null. So accessing null value will get you Object reference not set to an instance of object.
You can change your old implementation like below:
public static T Read<T>(string variable, int arraySize=10)
{
object value = HttpContext.Current.Session[variable];
if(typeof(T).IsArray && value == null)
{
//array requires size I personally prefer to have
//differnt read method for array.
return ((T)Activator.CreateInstance(typeof(T),arraySize));
}
if(!typeof(T).IsValueType && value == null)
{
//if it is not value type you can return new instance.
return ((T)Activator.CreateInstance(typeof(T)));
}
else if (value == null)
return default(T);
else
return ((T)value);
}
And access SessionHelper as below:
var sessionarray = SessionHelper.Read<object[]>("myarray",15);
....
// then use that sessionarray here.
....
You have to instantiate the CompDetails array before you start assigning values to it.
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
// Instantiate array
SessionHelper.CompDetails = new object[11];
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
// etc

Two Definitions for 'This' Method

Is it possible to have 2 definitions for the this method? I want users to be able to do both of the following: string value = myBranch[stringKey]; and also Branch child = myBranch[stringKey].
Is this possible? And if not can you suggest how I could design my class to achieve the same outside interaction (ie, accessing a child branch or value easily)?
public class Branch {
public enum BranchType {TYPE_BRANCH, TYPE_LEAF}
private string key = null;
private string value = null;
private Branch parent = null;
private Dictionary <string, Branch> children = new Dictionary <string, Branch>();
// Is it possible to have 2 'this' definitions?
// Def 1:
public Branch this[string attribKey] {
get
{
if (this.children.ContainsKey(attribKey))
return this.children[attribKey];
return Branch.EmptyBranch;
}
set
{
children[attribKey] = value;
value.Parent = this;
this.Type = BranchType.TYPE_BRANCH;
}
}
// Def 1:
public string this[string attribKey] {
get
{
return value;
}
set
{
value = value;
}
}
public string Key {
get { return key; }
}
}
No, the one rule for overloads is that Overloads cannot differ only by return value. Since myBranch is probably a Dictionary, it doesn't make sense that it would sometimes return a string and sometimes a Branch. I would write two functions:
GetBranchByKey and GetStringByKey to solve the overload problem.

SetValue on PropertyInfo instance error "Object does not match target type" c#

Been using a Copy method with this code in it in various places in previous projects (to deal with objects that have same named properties but do not derive from a common base class or implement a common interface).
New place of work, new codebase - now it's failing at the SetValue with "Object does not match target type" even on very simple examples... and it worked last week....
public static void Copy(object fromObj, object toObj)
{
Type fromObjectType = fromObj.GetType();
Type toObjectType = toObj.GetType();
foreach (System.Reflection.PropertyInfo fromProperty in
fromObjectType.GetProperties())
{
if (fromProperty.CanRead)
{
string propertyName = fromProperty.Name;
Type propertyType = fromProperty.PropertyType;
System.Reflection.PropertyInfo toProperty =
toObjectType.GetProperty(propertyName);
Type toPropertyType = toProperty.PropertyType;
if (toProperty != null && toProperty.CanWrite)
{
object fromValue = fromProperty.GetValue(fromObj,null);
toProperty.SetValue(toProperty,fromValue,null);
}
}
}
}
private class test
{
private int val;
private string desc;
public int Val { get { return val; } set { val = value; } }
public string Desc { get { return desc; } set { desc = value; } }
}
private void TestIt()
{
test testo = new test();
testo.Val = 2;
testo.Desc = "TWO";
test g = new test();
Copy(testo,g);
}
Hopefully someone can point out where I am being daft???
Try:
toProperty.SetValue(toObj,fromValue,null);
You are trying to pass in the property (toProperty) as the target object, instead of toObj. For info, if you are doing lots of this, maybe consider HyperDescriptor, which can vastly reduce the reflection cost.
Should be
toProperty.SetValue(toObj,fromValue,null);

Categories