Luatable equivalent in C#? - c#

I've been looking for a way to make a table like thing in C# (3.5), but still have come up empty. Basically I want to do this
var myClassVar = new myClass();
myClassVar["hello"]["world"] = "hello world";
myClassVar["hello"][0] = "swapped";
myClassVar[0][0] = "test";
myClassVar["hello"]["to"]["the"]["world"] = "again";
myClassVar[0][1][0][0] = "same as above sorta";
I'm trying to create this type of class to parse a file format I've created for storing data. Does anyone know of something like this?

public class LuaTable
{
private Dictionary<object, dynamic> properties = new Dictionary<object, dynamic>();
public dynamic this[object property]
{
get
{
if (properties.ContainsKey(property))
return properties[property];
LuaTable table = new LuaTable();
properties.Add(property, table);
return table;
}
set
{
if (!properties.ContainsKey(property))
properties.Add(property, value);
else
properties[property] = value;
}
}
}
You can use it exactly how you want to:
var myClassVar = new LuaTable();
myClassVar["hello"]["world"] = "hello world";
myClassVar["hello"][0] = "swapped";
myClassVar[0][0] = "test";
myClassVar["hello"]["to"]["the"]["world"] = "again";
myClassVar[0][1][0][0] = "same as above sorta";
string s1 = myClassVar["hello"]["world"]; // = "hello world"
string s2 = myClassVar["hello"][0]; // = "swapped"
string s3 = myClassVar[0][0]; // = "test"
string s4 = myClassVar["hello"]["to"]["the"]["world"]; // = "again"
string s5 = myClassVar[0][1][0][0]; // = "same as above sorta"
Edit: I just realized C# 3.5 doesn't have dynamic, so here's a version that simply uses generics. I hope that this is fine (since you really have to have all of the child properties of your table be of the same type (in this case, string):
public class LuaTable<T> where T : class
{
private bool isValue;
private T value = null;
private Dictionary<object, LuaTable<T>> properties = new Dictionary<object, LuaTable<T>>();
public static implicit operator LuaTable<T>(T val)
{
if (val is LuaTable<T>)
return (LuaTable<T>)val;
return new LuaTable<T>() { isValue = true, value = val };
}
public static implicit operator T(LuaTable<T> table)
{
if (table.isValue)
return table.value;
return table;
}
public LuaTable<T> this[object property]
{
get
{
if (isValue)
return null;
if (properties.ContainsKey(property))
return properties[property];
LuaTable<T> table = new LuaTable<T>();
properties.Add(property, table);
return table;
}
set
{
if (!properties.ContainsKey(property))
properties.Add(property, value);
else
properties[property] = value;
}
}
}
To use it, it's almost exactly the same as above. Just change the first line:
var myClassVar = new LuaTable<string>();

Related

Retrieve a Customized String Value

Goal:
Retrieve a string value that is "1_2_3" om the code myListAnimals. In the future, the value can be random.
I need to add a "_" between numbers.
Problem:
I don't know how to do it by using LINQ?
public class Animal
{
private void int _number;
private void string _name;
private bool display;
public int Number
{
get { return _number;}
set { _number = value; }
}
public int Name
{
get { return _name;
set { _name = value; }
}
public bool Display
{
get { return display;
set { display = value; }
}
}
List<Animal> myListAnimal = new List<Animal>
Animal myAnimal = new List<Animal>
myAnimal.Number = 1;
myAnimal.Name = "Dog";
myAnimal.Display = True;
myAnimals.add(myAnimal )
Animal myAnimal2 = new List<Animal>
myAnimal2.Number = 2;
myAnimal2.Name = "Cat";
myAnimal2.Display = True;
myAnimals.add(myAnimal2)
Animal myAnimal3 = new List<Animal>
myAnimal3.Number = 3;
myAnimal3.Name = "Pig";
myAnimal3.Display = True;
myAnimals.add(myAnimal3)
Animal myAnimal4 = new List<Animal>
myAnimal4.Number = 4;
myAnimal4.Name = "Sheep";
myAnimal4.Display = false;
myAnimals.add(myAnimal4)
Note: Your code sample isn't valid C#. I assume that you can fix that (it's pretty simple basic changes that need to be made). That said:
Yes, you can use LINQ to concatenate strings, which is ultimately what you're doing.
var concat = myListAnimal
.Where(a => a.Display)
.Select(a => a.Number.ToString())
.Aggregate((current, next) => current + "_" + next);
Console.WriteLine(concat);
Would output with your data:
1_2_3
Where() filters the values where Display != true
Select() projects the number values to a sequence of strings
and Aggregate() does the concatenation.
your code is not valid. First fix it and try this.
var concat =string.Join("_", myListAnimal.Select(a => a.Number).ToArray());
Try using StringBuilder and ForEach extension method.
StringBuilder sb = new StringBuilder();
myAnimals.ForEach(x=> sb.AppendFormat("{0}_",x.Number));

Public class is inaccessible due to protection level; Constructor is public

I have a class that is public, ArticleDao, but when I try to use it in another file, it says "ArticleDao is inaccessible due to its protection level." Here is the entire class:
class ArticleDao : IArticleDao
{
private readonly ContentManager _contentManager;
private static readonly char[] DelimiterChars = { '|', '\n' };
private const int ArticlePagingSize = 500;
public ArticleDao()
{
_contentManager = new ContentManager();
}
private Image GetImage(XElement element)
{
var image = new Image();
if (String.IsNullOrEmpty((String)element))
{
return image;
}
XElement imageElement = element.Element("img");
if (imageElement != null)
{
image.Url = (String)imageElement.Attribute("src");
}
return image;
}
private Link GetLink(XElement element)
{
var link = new Link();
if (String.IsNullOrEmpty((String)element))
{
return link;
}
XElement anchorElement = element.Element("a");
if (anchorElement != null)
{
link.Url = (String)anchorElement.Attribute("href");
link.Text = (String)anchorElement;
}
return link;
}
public Article GetArticle(long id, string html)
{
var a = new Article();
long testid = 556;
if (id == testid)
{
var x = 1;
}
XDocument xdoc = XDocument.Parse(html);
var xElement = xdoc.Element("root");
if (xElement != null)
{
XElement articleElem = xElement.Element("Event");
if (articleElem != null)
{
a = new Article();
a.Id = id.ToString(CultureInfo.InvariantCulture);
a.Title = (String)articleElem.Element("Title");
a.PublishedDate = GetDateTime((String)articleElem.Element("PublishedDate"));
a.SubHeader = (String)articleElem.Element("SubHeader");
a.Image = GetImage(articleElem.Element("Image"));
a.Caption = (String)articleElem.Element("Caption");
a.Body = (String)articleElem.Element("Body");
a.Url = GetLink(articleElem.Element("Url"));
}
}
return a;
}
public Article GetArticle(Int64 ektronContentId)
{
var item = _contentManager.GetItem(ektronContentId);
return GetArticle(ektronContentId, item.Html);
}
public IEnumerable<Article> GetArticles(Int64 folderId)
{
int count;
IEnumerable<Article> articles = new List<Article>(ArticlePagingSize);
do
{
var criteria = new ContentCriteria();
criteria.AddFilter(ContentProperty.FolderId, CriteriaFilterOperator.EqualTo, folderId);
criteria.PagingInfo.RecordsPerPage = ArticlePagingSize;
var articleContentData = _contentManager.GetList(criteria);
count = articleContentData == null ? 0 : articleContentData.Count;
articles = articles.Concat(_contentManager.GetList(criteria)
.Select(i => GetArticle(i.Id, i.Html)));
} while (count == ArticlePagingSize);
return articles;
}
private DateTime GetDateTime(string date)
{
DateTime dt;
DateTime.TryParse(date, out dt);
return dt;
}
}
The constructor is public. I even tried replacing all instances of "private" with "public," but it still says that it is inaccessible. This is the line where I'm trying to invoke it:
private static IArticleDao _articleDao;
public static IArticleDao ArticleDao
{
get { return _articleDao ?? (_articleDao = new ArticleDao()); }
}
Where it says "_articleDao = new ArticleDao()" is where the error is.
I'm especially confused because to create ArticleDao and IArticleDao, I essentially just copied EventDao and IEventDao and replaced "Event" with "Article." This works:
private static IEventDao _eventDao;
public static IEventDao EventDao
{
get { return _eventDao ?? (_eventDao = new EventDao()); }
}
but ArticleDao does not work.
The class itself isn't public. It's internal. (The default accessibility for anything is the smallest legal accessibility option, which for a non-nested class, is internal. You have specified no accessibility option explicitly.)
You class ArticleDao is a internal, as if you don't specify any accessibility modifier, the default in C# is internal. To resolve this issue you may think of declaring it public
public class ArticleDao : IArticleDao
{
...
}
The class' default access level is internal. Internal types or members are accessible only within files in the same assembly.
You probably want to specify
public class ArticleDao...
The constructor accessibility is not the same as the class access level, and if something is hidden by the class access modifier you cannot access any of its members regardless of their access modifier.

How to assign value to property class when giving a object as parameter?

Sorry if the title does not reflect what I actually want.
I'm creating a generic class for selecting, updating, inserting and deleting dates from and to a database.
Basically, I want a function that gives me back an ObservableCollection<"can be anything"> ==> Where anything is a class and not strings. I would like to know if it is possible to do this, if yes, please,help me how I can achieve this.
this is my starting point:
//class a
public static ObservableCollection<ContactPerson> contactPersons = new ObservableCollection<ContactPerson>();
public static ObservableCollection<ContactPerson> getContactPerson()
{
contactPersons = (ObservableCollection<ContactPerson>)DBConnection.GetDataOutDatabase(typeof(ContactPerson), "Contactpersoon");
return contactPersons;
}
//class b
public static Object GetDataOutDatabase(Type myType,String table)
{
ObservableCollection<Object> objecten = new ObservableCollection<Object>();
string sql = "SELECT * FROM " + table;
DbDataReader reader = Database.GetData(sql);
while (reader.Read())
{
objecten.Add(Create(myType, reader));
}
return objecten;
}
private static Object Create(Type myType, IDataRecord record)
{
PropertyInfo[] myPropertyInfo = myType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < myPropertyInfo.Length; i++)
{
PropertyInfo myPropInfo = (PropertyInfo)myPropertyInfo[i];
String name = myPropInfo.Name;
Type type = myPropInfo.PropertyType;
}
return null;
}
And this is what I ultimately want to get. Is this possible?
//ContactPerson cp = new ContactPerson();
//cp.ID = (record["ID"].ToString());
//cp.Name = record["Name"].ToString();
//cp.Company = record["Company"].ToString();
//cp.JobTitle = new ContactPersonTitle()
//{
// Name = record["JobTitle"].ToString(),
//};
//cp.JobRole = new ContactPersonType()
//{
// Name = record["JobRole"].ToString(),
//};
//cp.City = record["City"].ToString();
//cp.Email = record["Email"].ToString();
//cp.Phone = record["Phone"].ToString();
//cp.Cellphone = record["Cellphone"].ToString();
Many thanks!
You can actually do this with reflection in generic methods.
public class DBConnection
{
public static ObservableCollection<T> GetDataOutDatabase<T>(string table)
{
var objecten = new ObservableCollection<T>();
string sql = "SELECT * FROM " + table;
DbDataReader reader = Database.GetData(sql);
while (reader.Read())
{
objecten.Add(Create<T>(reader));
}
return objecten;
}
public static T Create<T>(IDataRecord record)
{
var properties = typeof(T).GetProperties();
var returnVal = Activator.CreateInstance(typeof(T));
properties.ToList().ForEach(item =>
{
try
{
if (item.PropertyType.IsPrimitive)
{
item.SetValue(returnVal, Convert.ChangeType(record[item.Name].ToString(), item.PropertyType),null);
}
else
{
object[] parameters = {record};
var value =
typeof(DBConnection).GetMethod("Create").MakeGenericMethod(item.PropertyType).Invoke(null, parameters);
item.SetValue(returnVal,value,null);
}
}
catch
{
Write("Property Not Found");
}
});
return (T)returnVal;
}
}
The example above does assume that all properties names match the column names you are retrieving from your database communication. For instance in the ContactPersonTitle above rather than Name you would need to have JobTitle as the property name.
Not as you are currently doing it. You should look into the entity framework which allows translation of database tables datacollections.
have a look at:
http://www.codeproject.com/Articles/363040/An-Introduction-to-Entity-Framework-for-Absolute-B

C# Object Reference : How can i do it?

This is class Test
public class Test
{
public string mystr;
}
And i call it from method :
string my = "ABC";
Test test = new Test();
test.mystr = my;
test.mystr = "";
Result of a bit code above are : my = "ABC" and test.mystr = ""
How can I set my to empty string "" when I change test.mystr = ""?
If I understand correctly, you want the variables my and test.myStr to be linked, so if one changes, the other changes?
The answer is simple: It cannot!
A string is an immutable class. Multiple references can point to a string instance, but once this instance is modified, a string instance is created with the new value. So a new reference is assigned to a variable, while the other variables still point to the other instances.
There is a workarounds, but I suspect you will not be happy with it:
public class Test
{
public string mystr;
}
Test myTest1 = new Test { myStr = "Hello" };
Test myTest2 = myTest1;
Now, if you change myTest1.myStr, the variable myTest2.myStr will also be modified, but that is simply because the myTest1 and myTest2 are the same instances.
There are other solutions like these, but the all come down to the same aspect: A class holding a reference to a string.
Strings in .NET are immutable and don't work like that. One approach you could try is to use a mutable wrapper for the strings.
public class StringReference
{
public string Value {get; set;}
public StringReference(string value)
{
Value = value;
}
}
public class Test
{
internal StringReference mystr;
}
StringReference my = new StringReference("ABC");
Test test = new Test();
test.mystr = my;
test.mystr.Value = "";
// my.Value is now "" as well
string my = "ABC";
Test test = new Test();
Note here, that there is no relationship between your Test class and the string my. I am not entirely sure what you are trying to achieve, but we could do it like this:
public class Test
{
private string _mystr;
private Action<string> _action;
public Test(Action<string> action)
{
_action = action;
}
// Let's make mystr a property
public string mystr
{
get { return _mystr; }
set
{
_mystr = value;
_action(_mystr);
}
}
}
Now you can do this:
string my = "ABC";
Test test = new Test((mystr) => { if(string.IsNullOrEmpty(mystr)) my = ""; });
test.mystr = my;
test.mystr = "";

Getting all nested types from ParameterInfo

For an application I'm working on I'm trying to display a template that will show what the parameters for a (runtime-determined) method look like. The test case I'm working on should show "PERSON = (FIRST = first; LAST = last);", where the parameter named Person has type Name, and Name has two properties, First and Last. The following code instead shows "PERSON = ();".
GetNestedTypes is not returning anything, any ideas why?
public static string GetParameterTemplate(MethodInfo method)
{
StringBuilder output = new StringBuilder();
foreach (ParameterInfo pi in method.GetParameters())
{
output.Append(parameterTemplateHelper(pi.Name, pi.ParameterType));
}
return output.ToString();
}
private static string parameterTemplateHelper(string pName, Type pType)
{
string key = pName.ToUpper();
string value = "";
if (pType.IsPrimitive)
{
// it's a primitive
value = pName.ToLower();
}
else if (pType.IsArray)
{
if (pType.GetElementType().IsPrimitive)
{
// array of primitives
value = String.Format("{0}1, {0}2;", pName.ToLower());
}
else
{
// array of objects
StringBuilder sb = new StringBuilder();
foreach (Type t in pType.GetElementType().GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
{
sb.Append(parameterTemplateHelper(t.Name, t));
}
value = String.Format("({0}), ({0});", sb);
}
}
else
{
// object
StringBuilder sb = new StringBuilder();
Type[] junk = pType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
foreach (Type t in pType.GetNestedTypes())
{
sb.Append(parameterTemplateHelper(t.Name, t));
}
value = String.Format("({0});", sb.ToString());
}
string output = key + " = " + value.ToString();
return output;
}
Your code is looking for nested types - that is, other types declared within Person. That's not at all the same as looking for properties within Person.
Here's a class with nested types:
public class Name
{
public class Nested1 {}
public class Nested2 {}
}
Here's a class with properties:
public class Name
{
public string Name { get; set; }
public string Name { get; set; }
}
My guess is that your situation is much more like the second one than the first... so use Type.GetProperties instead of Type.GetNestedTypes.

Categories

Resources