I would like to create a generic list which takes in a generic class. But the problem is i can't access the variables inside the generic class and i've seen people leave the interface empty and wonder how i should do to access the variables in the class.
public List<IAttributeInterface> attributes = new List<IAttributeInterface>();
public void AddAttribute<T>(T attribute, T value)
for (int i = 0; i < attributes.Count; i++)
{
if (attributes[i].key == attribute)
{
attributes[i].value = value;
return;
}
}
attributes.Add(new Attribute(attribute, value));
}
public class Attribute<T> where T : IAttributeInterface
{
public T key;
public T value;
public Attribute(T key, T value)
{
this.key = key;
this.value = value;
}
}
public interface IAttributeInterface
{
}
It is necessary to add properties inside of interfaces:
public interface IAttributeInterface<T>
{
T Key { get; set; }
T Value { get; set; }
}
Then we need to implement this generic interface in class to be able to create instance of object:
public class Attribute<T> : IAttributeInterface<T>
{
public T Key { get; set ; }
public T Value { get ; set; }
public Attribute(T key, T value)
{
this.Key = key;
this.Value = value;
}
}
and your method will look like this:
public List<IAttributeInterface<string>> attributes =
new List<IAttributeInterface<string>>();
public void AddAttribute<T>(T attribute, T value) where T: IAttributeInterface<string>
{
for (int i = 0; i < attributes.Count; i++)
{
if (attributes[i].Key == attribute.Key)
{
attributes[i].Value = value.Value;
return;
}
}
attributes.Add(new Attribute<string>("key", "value"));
}
and it is possible to use like that:
AddAttribute(new Attribute<string>("foo key 0", "foo value 0"),
new Attribute<string>("foo key 1", "foo value 1"));
You need to add {get;set;} for those attributes (properties) in the interface.
public interface IAttributeInterface<T>
{
T Key { get; set; }
T Value { get; set; }
}
Related
I want the value to be initialized according to the attribute When Instance is created.
class FieldAttr : Attribute
{
public readonly string key;
public Key_FieldAttr(string key)
{
this.key = key;
}
}
class CtorAttr : Attribute
{
}
static string FromTable(string key)
{
// will return localized string of key from table.
}
...
class LocalizedMetadata
{
[FieldAttr("NAME")]
public string Name { get; }
[FieldAttr("DESC")]
public readonly string Description;
[CtorAttr]
public LocalizedMetadata(string header)
{
// I want "Key" attribute to do as below...
// this.Name = FromTable(header + "NAME");
// this.Description = FromTable(header + "DESC");
}
}
public static void Main(string[] args)
{
var foo = new LocalizedMetadata("UNITY_");
Console.WriteLine(foo.Name); // = FromTable("UNITY_NAME");
Console.WriteLine(foo.Description); // = FromTable("UNITY_DESC");
}
I don't know where to attach what kind of Attribute (Field, Construction, Class) will be possible.
I looked up documents about Attribute and Reflection, but I don't know if this is possible.
I think below solution will solve your problem.
class LocalizedMetadata
{
[FieldAttr("NAME")]
public string Name { get; set; }
[FieldAttr("DESC")]
public string Description { get; set; }
public LocalizedMetadata(string header)
{
foreach (var property in typeof(LocalizedMetadata).GetProperties())
{
foreach (var attr in property.GetCustomAttributes(false))
{
FieldAttr fieldAttr = (FieldAttr)attr;
property.SetValue(this, header + fieldAttr.Key);
}
}
}
}
public static void Main(string[] args)
{
var foo = new LocalizedMetadata("UNITY_");
Console.WriteLine(foo.Name);
Console.WriteLine(foo.Description);
}
Output:
UNITY_NAME
UNITY_DESC
I have two classes OnlineBoolTag and OnlineDoubleTag. I add these objects to a list and want to get the Value of different types. How to return Value property of double or bool?
public class OnlineDoubleTag : IOnlineTag
{
public string Name { get; set; }
public double Value { get; set; }
}
public class OnlineBoolTag : IOnlineTag
{
public string Name { get; set; }
public bool Value { get; set; }
}
Add objects to a list:
var onlinetags = new List<IOnlineTag>();
onlinetags.Add(new OnlineBoolTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineDoubleTag { Name = "Float1", Value = 777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine(tag.*****Value*****);
}
You can use dynamic instead of object
interface IOnlineTag
{
public dynamic GetValue();
}
public class OnlineDoubleTag : IOnlineTag
{
public string Name { get; set; }
public double Value { get; set; }
public dynamic GetValue()
{
return this.Value;
}
}
public class OnlineBoolTag : IOnlineTag
{
public string Name { get; set; }
public bool Value { get; set; }
public dynamic GetValue()
{
return this.Value;
}
}
public static void Main()
{
var onlinetags = new List<IOnlineTag>();
onlinetags.Add(new OnlineBoolTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineDoubleTag { Name = "Float1", Value = 7777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine($"{tag.GetValue()} {tag.GetValue().GetType()}");
}
// Value: True Type: System.Boolean
// Value: 7777.22 Type: System.Double
}
Using dynamic will help here, as Guy's answer points out. We can simplify this even further though, by defining the property Value to be of type dynamic itself. This removes the need to implement the interface for GetValue method. Instead, we can do this:
public class OnlineTag
{
public string Name {get;set;}
public dynamic Value {get;set;}
}
public class Program
{
public static void Main(string[] args)
{
var onlinetags = new List<OnlineTag>();
onlinetags.Add(new OnlineTag { Name = "Bool1", Value = true });
onlinetags.Add(new OnlineTag { Name = "Float1", Value = 7777.22 });
foreach (var tag in onlinetags)
{
Console.WriteLine($"{tag.Value} {tag.Value.GetType()}");
//prints the below
//True System.Boolean
//7777,22 System.Double
}
}
}
The pitfall with this is that defining Value as dynamic allows you to reassign a value of totally different type later on in your code. For example, the below code will not throw any errors:
Console.WriteLine($"{onlinetags[0].Value} {onlinetags[0].Value is bool}"); //prints True True
onlinetags[0].Value = 123M;
Console.WriteLine($"{onlinetags[0].Value} {onlinetags[0].Value.GetType()}"); // prints 123 System.Decimal
So my dilemma is that in order to access IntThing's or StringThing's MyProperty from UtilityThing<T>, I'm defining an interface with MyProperty and using it as the generic constraint on T in UtilityThing<T>. This is working, but seems redundant given that the same property is already defined in the abstract base. Am I missing a facet of design here, or is this actually the way it needs to be done in this instance?
public interface IThing {
string MyProperty { get; set; }
}
public abstract class Thing<T> {
protected string _MyProperty;
public abstract string MyProperty { get; set; }
public T OtherProperty { get; set; }
public string CommonMethod() {
return MyProperty + "foobar";
}
}
public class IntThing : Thing<int?>, IThing {
public override string MyProperty {
get { return _MyProperty; }
set { _MyProperty = value + OtherProperty.ToString(); }
}
}
public class StringThing: Thing<string>, IThing {
public override string MyProperty {
get { return _MyProperty; }
set { _MyProperty = OtherProperty + value; }
}
}
public class UtilityThing<T> where T: IThing, new() {
public T DoIt(SomeContext someContext, string name) {
string contextVal = someContext.GetValue(name);
var thing = new T { MyProperty = contextVal }
return thing;
}
}
You'll need to introduce a new generic type. Once the new type is introduced you can eliminate the need of the interface.
public class UtilityThing<T, I> where T : Thing<I>, new()
{
public T DoIt(SomeContext someContext, string name)
{
string contextVal = someContext.GetValue(name);
var thing = new T { MyProperty = contextVal };
return thing;
}
}
And you can use it like this:
var utility = new UtilityThing<IntThing, int?>();
I'm basically reading a config file
[Section]
Key=value
Where the value can be either a string, an integer, a double, or a boolean value.
While working in this context, I have a class that looks like this...
public class Setting
{
public string Section {get; set;}
public string Key {get; set;}
public <string, int, double, or bool> Value {get; set;}
public Setting(string section, string key, <string, int, double, or bool> value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//if Value is an int, call third-party code to write an integer to the config file.
//if Value is a string, call third-party code to write a string to the config file.
//...
}
}
In this situation, what is the accepted way to handle the Value property of this class?
In addition, I'd like to be able to store a bunch of these objects in an Array, List, or other types of collections.
UPDATE:
I'm not reading/writing to the configuration file directly, that part of the code is not controlled by me. Basically, I need to call different functions in the third-party code, based on the type of Value
UPDATE:
One thought was to use generics, and have a class like this...
public class Setting<T>
{
public string Section { get; set; }
public string Key { get; set; }
public T Value { get; set; }
public Setting(string section, string key, T value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
But then I'd only be able to store a single type of setting in a List.
System.Collections.Generic.List<Setting<string>> settings = new List<Setting<string>>();
So I'd have to have a list for each type of setting.
UPDATE:
Another option might be to use and interface, and classes for each type of setting that implement the interface...
interface ISetting
{
string Section { get; set; }
string Key { get; set; }
void Write();
}
public class StringSetting : ISetting
{
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public StringSetting(string section, string key, string value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//Call third-party code to write the setting.
}
}
But that seems like a lot of duplicate code, so making changes in the future might be error prone.
UPDATE:
Another option, is to make Value a dynamic type.
public class DynamicSetting
{
public string Section { get; set; }
public string Key { get; set; }
public dynamic Value { get; set; }
public DynamicSetting(string section, string key, dynamic value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
Then I can create a bunch of DynamicSetting objects, and store them in a collection like I want.
DynamicSetting IntSetting = new DynamicSetting("Section", "Key", 1);
DynamicSetting StringSetting = new DynamicSetting("Section", "Key", "1");
DynamicSetting DoubleSetting = new DynamicSetting("Section", "Key", 1.0);
System.Collections.Generic.List<DynamicSetting> settings = new List<DynamicSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(DynamicSetting setting in settings)
{
setting.Write();
}
UPDATE:
I could also make Value an object
public class ObjectSetting
{
public string Section { get; set; }
public string Key { get; set; }
public object Value { get; set; }
public ObjectSetting(string section, string key, object value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
case TypeCode.Double:
//Call third-party code to write a string
break;
default:
break;
}
}
}
And it would work just like dynamic
ObjectSetting IntSetting = new ObjectSetting("Section", "Key", 1);
ObjectSetting StringSetting = new ObjectSetting("Section", "Key", "1");
ObjectSetting DoubleSetting = new ObjectSetting("Section", "Key", 1.0);
System.Collections.Generic.List<ObjectSetting> settings = new List<ObjectSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(ObjectSetting setting in settings)
{
setting.Write();
}
The simplest way is to accept Value as an object in the constructor and the setter, both of which would validate the Type against your list of valid types. Use a Switch in your Write method to determine which third-party code to call. You can store all your Settings in a single collection. Alternatively, you could write overloads for the constructor and a SetValue method. That's a little more code, but would provide design time type-checking.
Example for ISettingValue:
public interface ISettingValue
{
void Write();
}
public class StringSetting : ISettingValue
{
readonly string _data;
public StringSetting(string data) => _data = data;
public void Write()
{
//Call third-party code to write the string (value of _data).
}
}
public class IntSetting : ISettingValue
{
readonly int _data;
public IntSetting(int data) => _data = data;
public void Write()
{
//Call third-party code to write the integer (value of _data).
}
}
public class Setting
{
public string Section { get; set; }
public string Key { get; set; }
public ISettingValue Value { get; set; }
public Setting(string section, string key, ISettingValue value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
Value.Write();
}
}
Maybe something like that?
public abstract class Setting {
public abstract Type keyType { get; }
public string Key { get; protected set; }
public object value { get; protected set; }
protected abstract Action writer { get; }
public void Write() => writer();
}
public class Setting<T> : Setting {
public override Type keyType => typeof(T);
protected override Action writer => () => typeWriter(Value);
public string Section { get; set; }
public T Value {get; set;}
private Action<T> typeWriter { get; }
public Setting(string section, string key, T value, Action<T> writer) {
Section = section;
Key = key;
this.value = Value = value;
typeWriter = writer;
}
}
public class Usage {
private List<Setting> settings = new List<Setting>() {
new Setting<double>("", "x", 10, n => Debug.WriteLine(n % 4)),
new Setting<string>("", "y", "abc", s => Debug.WriteLine(s.ToUpper())),
new Setting<bool>("", "z", true, b => Debug.Write(!b)),
};
public Usage() {
foreach (var s in settings) {
Debug.Write($"{s.keyType.Name} {s.Key} =");
s.Write();
}
}
}
I'm working on a project where I have some recursive data structure and I want to create a fixture for it.
The data structure is XmlCommandElement, it has a single method ToCommand that converts XmlCommandElement to Command.
Each node on the tree can be a XmlCommandElement and/or XmlCommandPropertyElement.
Now, in order to test the behaviour of the method ToCommand I want to fetch XmlCommandElement with some arbitrary data.
I want to control the depth of the tree and the amount of instances of XmlCommandElement and/or XmlCommandPropertyElement per node.
So here is the code I'm using for the fixture:
public class XmlCommandElementFixture : ICustomization
{
private static readonly Fixture _fixture = new Fixture();
private XmlCommandElement _xmlCommandElement;
public int MaxCommandsPerDepth { get; set; }
public int MaxDepth { get; set; }
public int MaxPropertiesPerCommand { get; set; }
public XmlCommandElementFixture BuildCommandTree()
{
_xmlCommandElement = new XmlCommandElement();
var tree = new Stack<XmlCommandElementNode>();
tree.Push(new XmlCommandElementNode(0, _xmlCommandElement));
while (tree.Count > 0) {
var node = tree.Pop();
node.Command.Key = CreateRandomString();
node.Command.Properties = CreateProperties();
if (MaxDepth > node.Depth) {
var commands = new List<XmlCommandElement>();
for (var i = 0; i < MaxCommandsPerDepth; i++) {
var command = new XmlCommandElement();
tree.Push(new XmlCommandElementNode(node.Depth + 1, command));
commands.Add(command);
}
node.Command.Commands = commands.ToArray();
}
}
return this;
}
public void Customize(IFixture fixture)
{
fixture.Customize<XmlCommandElement>(c => c.FromFactory(() => _xmlCommandElement)
.OmitAutoProperties());
}
private static string CreateRandomString()
{
return _fixture.Create<Generator<string>>().First();
}
private XmlCommandPropertyElement[] CreateProperties()
{
var properties = new List<XmlCommandPropertyElement>();
for (var i = 0; i < MaxPropertiesPerCommand; i++) {
properties.Add(new XmlCommandPropertyElement {
Key = CreateRandomString(),
Value = CreateRandomString()
});
}
return properties.ToArray();
}
private struct XmlCommandElementNode
{
public XmlCommandElementNode(int depth, XmlCommandElement xmlCommandElement)
{
Depth = depth;
Command = xmlCommandElement;
}
public XmlCommandElement Command { get; }
public int Depth { get; }
}
}
And this is how I'm using it:
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
This works perfectly fine! but the issue I have with it is it isn't generic, the whole point of AutoFixture at least as far as I know is to avoid making specific fixtures.
So what I would really like to do is something like this (found it here but it doesn't work for me.):
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandElement), 3));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandPropertyElement), 4));
xmlCommandElement = fixture.Create<XmlCommandElement>();
Here is all the code for reference:
Interfaces:
public interface ICommandCollection : IEnumerable<ICommand>
{
ICommand this[string commandName] { get; }
void Add(ICommand command);
}
public interface ICommandPropertyCollection : IEnumerable<ICommandProperty>
{
string this[string key] { get; }
void Add(ICommandProperty property);
}
public interface ICommandProperty
{
string Key { get; }
string Value { get; }
}
public interface ICommand
{
ICommandCollection Children { get; set; }
string Key { get; }
ICommandPropertyCollection Properties { get; }
}
public interface ICommandConvertible
{
ICommand ToCommand();
}
Classes:
public sealed class CommandPropertyCollection : ICommandPropertyCollection
{
private readonly IDictionary<string, ICommandProperty> _properties;
public CommandPropertyCollection()
{
_properties = new ConcurrentDictionary<string, ICommandProperty>();
}
public string this[string key]
{
get
{
ICommandProperty property = null;
_properties.TryGetValue(key, out property);
return property.Value;
}
}
public void Add(ICommandProperty property)
{
_properties.Add(property.Key, property);
}
public IEnumerator<ICommandProperty> GetEnumerator()
{
return _properties.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class CommandProperty : ICommandProperty
{
public CommandProperty(string key, string value)
{
Key = key;
Value = value;
}
public string Key { get; }
public string Value { get; }
}
public sealed class Command : ICommand
{
public Command(string key, ICommandPropertyCollection properties)
{
Key = key;
Properties = properties;
}
public ICommandCollection Children { get; set; }
public string Key { get; }
public ICommandPropertyCollection Properties { get; }
}
public class XmlCommandPropertyElement : ICommandPropertyConvertible
{
[XmlAttribute("key")]
public string Key { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
public ICommandProperty ToCommandProperty()
{
return new CommandProperty(Key, Value);
}
}
Finally, the class I'm trying to test is as follow:
public class XmlCommandElement : ICommandConvertible
{
[XmlArray]
[XmlArrayItem("Command", typeof(XmlCommandElement))]
public XmlCommandElement[] Commands { get; set; }
[XmlAttribute("key")]
public string Key { get; set; }
[XmlArray]
[XmlArrayItem("Property", typeof(XmlCommandPropertyElement))]
public XmlCommandPropertyElement[] Properties { get; set; }
public ICommand ToCommand()
{
ICommandPropertyCollection properties = new CommandPropertyCollection();
foreach (var property in Properties) {
properties.Add(property.ToCommandProperty());
}
ICommand command = new Command(Key, properties);
return command;
}
}
The test itself looks like this:
namespace Yalla.Tests.Commands
{
using Fixtures;
using FluentAssertions;
using Ploeh.AutoFixture;
using Xbehave;
using Yalla.Commands;
using Yalla.Commands.Xml;
public class XmlCommandElementTests
{
[Scenario]
public void ConvertToCommand(XmlCommandElement xmlCommandElement, ICommand command)
{
$"Given an {nameof(XmlCommandElement)}"
.x(() =>
{
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
});
$"When the object is converted into {nameof(ICommand)}"
.x(() => command = xmlCommandElement.ToCommand());
"Then we need to have a root object with a key"
.x(() => command.Key.Should().NotBeNullOrEmpty());
"And 4 properties as its children"
.x(() => command.Properties.Should().HaveCount(4));
}
}
}
Thanks to Mark Seemann! the final solution looks like this:
public class RecursiveCustomization : ICustomization
{
public int MaxDepth { get; set; }
public int MaxElements { get; set; }
public void Customize(IFixture fixture)
{
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(MaxDepth));
fixture.RepeatCount = MaxElements;
}
}
And can be used like this:
xmlCommandElement = new Fixture().Customize(new RecursiveCustomization {
MaxDepth = 2,
MaxElements = 3
}).Create<XmlCommandElement>();
You can fairly easily create a small tree by changing the Fixture's recursion behaviour:
[Fact]
public void CreateSmallTree()
{
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(recursionDepth: 2));
var xce = fixture.Create<XmlCommandElement>();
Assert.NotEmpty(xce.Commands);
}
The above test passes.