Subscribe to something like on object instance being assigned event - c#

Here is what I am trying to do. I am making a class which contains indexer for accessing fields within the class, and for adding/removing new fields. Basically the class is like a class with set of static and dynamic fields. I am using a dictionary for the indexer. My problem is that how would I find out and update the static object in the dictionary when the user explicitly reinitialized one of the field? example:
public class foo
{
}
public class bar
{
Dictionary<string, foo> dict = new Dictionary<string, foo>();
public bar()
{
//using reflection to initialize all fields
}
public foo this[string name]
{
get
{
return dict[name];
}
}
}
public class bar2:bar //Note: defined by the user, can't use get/setter to update it
{
public foo field1;
public foo field2;
public foo field3;
}
public static void main()
{
bar2 test = new bar2();
test.field1 = new foo();
test["field1"] //this points to the old field1. How can I update it automatically when test.field1 = new foo(); is called?
}
Some of you might suggest me to use reflection to do it, but what if the user called remove "field1" and added a new dynamic field called field1, I would want to return the new one created by the user instead of the one defined in the class.

If your users and defining fields then you will need to adjust your logic to dynamically look up the result every time. Luckily you can avoid most of the reflection overhead by storing the field in your dictionary.
Dictionary<string, FieldInfo> dict = new Dictionary<string, FieldInfo>();
public bar()
{
//If you are using reflection you should be getting this
FieldInfo info;
dict[info.Name] = info;
}
public foo this[string name]
{
get { return dict[name].GetValue(this); }
set { dict[name].SetValue(this, value); }
}

Related

C# callback for when a class with attribute got instantiated

Is there something like a callback for when when a class Foo with a specific attribute got instantiated?
A little like this pseudo code:
void OnObjectWithAttributeInstantiated(Type attributeType, object o) {
// o is the object with the attribute
}
So i was trying to create an attribute AutoStore. Imagine the following:
Given a class Foo with that tag:
[AutoStore]
public class Foo { ... }
Then (somewhere else in the code, no matter where) you instantiate that class
Foo f = new Foo()
I now want, that this object f will be automatically added to a list of objects (e.g. in a static class or something)
If there is no such way, do you have some ideas how to do a work-around?
Edit
I dont want to use a superclass which does that for purposes of clean code
Best regards Briskled
I don't think you can do that. Because attributes are there for you to discover at runtime. But a possible solution might be to create a factory to wrap the whole thing, like -
public class Factory
{
public static T Instantiate<T>() where T : class
{
// instantiate your type
T instant = Activator.CreateInstance<T>();
// check if the attribute is present
if (typeof(T).GetCustomAttribute(typeof(AutoStore), false) != null)
{
Container.List.Add(instant);
}
return instant;
}
}
public static class Container
{
public static List<object> List { get; set; } = new List<object>();
}
and then you can use it like -
Foo foo = Factory.Instantiate<Foo>();
foo.Bar = "Some Bar";

How to make setters that return a new instance of the class in C#? (for making objects immutable)

I have a class with several attributes that have getters and setters. I want to make the objects of this class immutable. I thought of giving the setters a return type instead of void like is done to the functions in System.Collections.Immutable classes. For now I did it like this:
MyImmutableClass
{
public int MyAttribute { get; }
public MyImmutableClass SetMyAttribute(int attribute)
{
return new MyImmutableClass(attribute, ...);
}
...
public MyImmutableClass(int attribute, ...)
{
MyAttribute = attribute;
...
}
}
Is this how it should be done or is there a better/nicer way? Can I moddify a normal setter for instance?
You should rather use a static factory method and use a private constructor, properties aren't made for this (because creating an object may be a lot of work -> use a method). You do everything in the create method, which gives you back an object that you can't modify anymore, by having readonly properties like you do:
public class MyImmutableClass
{
public int MyAttribute { get; }
private MyImmutableClass(int attribute, ...)
{
MyAttribute = attribute;
...
}
public static MyImmutableClass Create(int attribute)
{
return new MyImmutableClass(attribute, ...);
}
}
Then use it:
var myClass = MyImmutableClass.Create(2);

Accessing member by index via property

How can I access an element by index of a member List via a property? For example:
public class foo{
private List<type> list = new List<type>;
public List{
get{/*basically, what goes here?*/}
}
}
//Much later....
foo Foo = new foo();
Console.WriteLine(Foo.List[1]);
One thing to consider is what ability you want to provide to update the list. If you just expose the list as a get-only property, then there's nothing stopping someone from modifying the list:
public class foo{
private List<type> list = new List<type>;
public List<type> List{
get{return list}
}
}
//Much later....
foo Foo = new foo();
Foo.List.Clear(); // perfectly legal
If, however, you want a "read-only" list exposed, then you can expose the list as read-only:
public class foo{
private List<type> list = new List<type>;
public IList<type> List{
get{return list.AsReadOnly()}
}
}
//Much later....
foo Foo = new foo();
Foo.List.Clear(); // not possible
EDIT
Based on your comment to another question, it is unclear whether you want to expose the list as a property or access items by index. For the latter you can add an indexer to the class:
public class foo{
private List<type> list = new List<type>;
public type this[int i]{
get{return list[i]}
get{list[i] = value}
}
}
//Much later....
foo Foo = new foo();
Console.WriteLine(Foo[1]);
Since you already have a list, you can just return that list in the property
public class foo{
private List<type> list = new List<type>;
public List<type> List{
get{ return list; }
}
}

Dynamically add a Property to a System.object?

I got a list of different objects that I defined in different classes and I'd like to add a string property "Name" to all these objects. Is that possible ?
I don't have that much code to provide as my classes are very simple/classic ones.
Thanks in advance for any help !
(edit : I don't want to inherit from an abstract class that adds this property ! In fact, I don't want to modify at all my class that define my object. That's what i call "Dynamically" in the title.
What I want is something like :
myObject.AddProperty(string, "Name");
or
myObject.AddAttribute(string, "Name");
(I don't know how it is exactly called)
and then I can do :
myObject.Name = "blaaa";
Create an abstract class that all of your other classes could inherit:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
public class Foo : MyBaseClass
{
public MyBaseClass() { }
}
//Create instance of foo
Foo myFoo = new Foo();
//MyCommonString is accessible since you inherited from base
string commonString = myFoo.MyCommonString;
EDIT (per new requirement)
Since you don't want to touch the original classes in the DLL, I'd take this [similar] approach:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
//This class definition lives in the DLL and remains untouched
public class Foo
{
public Foo() { }
}
//This partial class definition lives in [insert new project name here]
public partial class Foo : MyBaseClass
{
public Foo () { }
}
Notice that Foo is now a partial class. You're not touching the existing class definition in the DLL, you're extending it.
EDIT (per newer new requirement)
Given your requirements (no editing of original class), what you're asking is not possible.
What you can do is to hard code a Hashtable named CustomProperties
Now you can fill this Hashtable with custom properties
Something like that:
MyClass myClass = new MyClass();
myClass.SetProperty("abc", 123);
myClass.SetProperty("bcd", "bla");
myClass.SetProperty("cde", DateTime.Now);
MessageBox.Show(myClass.GetProperty("abc").ToString());
class MyClass
{
private Hashtable MyProperties { get; set; }
public MyClass()
{
MyProperties = new Hashtable();
}
public object GetProperty(string name)
{
return MyProperties.Contains(name) ? MyProperties[name] : null;
}
public void SetProperty(string name, object value)
{
if (MyProperties.Contains(name))
MyProperties[name] = value;
else
MyProperties.Add(name, value);
}
}
You want to use the new C# 4.0 dynamic keyword:
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Value = 10;
var action = new Action<string>((l) => Console.WriteLine(l));
obj.WriteNow = action;
obj.WriteNow(obj.Value.ToString());
You can not do this with object, but the ExpandoObject will do just fine.
But... overuse dynamic typing and you'll find yourself in a maintenance nightmare in the near future.

Passing static parameters to a class

As far as I know you can can't pass parameters to a static constructor in C#.
However I do have 2 parameters I need to pass and assign them to static fields before I create an instance of a class. How do I go about it?
This may be a call for ... a Factory Method!
class Foo
{
private int bar;
private static Foo _foo;
private Foo() {}
static Foo Create(int initialBar)
{
_foo = new Foo();
_foo.bar = initialBar;
return _foo;
}
private int quux;
public void Fn1() {}
}
You may want to put a check that 'bar' is already initialized (or not) as appropriate.
You can't pass parameters to a static constructor, but you can pass parameters to the class itself - via generic type parameters.
Slightly crazy this idea, however, I'll just throw it out there anyway.
Make the class generic (with a TypeParam that will provide a parameter type) and place generic constraints on it (details in code example), then derive a new parameter type, which contains virtuals that you can use to read what they want the parameter values to be.
//base parameter type - provides the 'anchor' for our generic constraint later,
//as well as a nice, strong-typed access to our param values.
public class StaticParameterBase
{
public abstract string ParameterString{ get; }
public abstract MyComplexType ParameterComplex { get; }
}
//note the use of the new() generic constraint so we know we can confidently create
//an instance of the type.
public class MyType<TParameter> where TParameter:StaticParameterBase, new()
{
//local copies of parameter values. Could also simply cache an instance of
//TParameter and wrap around that.
private static string ParameterString { get; set; }
private static MyComplexType ParameterComplex { get; set; }
static MyType()
{
var myParams = new TParameter();
ParameterString = myParams.ParameterString;
ParameterComplex = myParams.ParameterComplex;
}
}
//e.g, a parameter type could be like this:
public class MyCustomParameterType : StaticParameterBase
{
public override string ParameterString { get { return "Hello crazy world!"; } }
public override MyComplexType { get {
//or wherever this object would actually be obtained from.
return new MyComplexType() { /*initializers etc */ };
}
}
}
//you can also now derive from MyType<>, specialising for your desired parameter type
//so you can hide the generic bit in the future (there will be limits to this one's
//usefulness - especially if new constructors are added to MyType<>, as they will
//have to be mirrored on this type as well).
public class MyType2 : MyType<MyCustomParameterType> { }
//then you'd use the type like this:
public static void main()
{
var instance = new MyType<MyCustomParameterType>();
//or this:
var instance2 = new MyType2();
}
I did consider a solution that employs custom type attributes applies to a type parameter, however this is easily a better way. However, you'll now be using your class always with a generic parameter type (unless you can use the deriving+specialisation trick) - possibly too clumsy for your liking.
I'd also prefer this over the other solutions presented here as it doesn't require creating any workarounds for the static initialisation - you can still use .Net's guarantee of single-time initialisation.
A word of warning - should you be reviewing your structure?
All that said - remember, though, since you can only parameterise the static once (or in this case, each uniquely parameterised static generic) - I would be asking myself why not just pull the code that is getting the parameters to give to the static, and place it in the static constructor in the first place? That way you don't actually have to resort to strange patterns like this!
I assume you mean static members of a class? In that case, you can do this:
public class MyClass
{
public static int MyInt = 12;
public static MyOtherClass MyOther = new MyOtherClass();
}
Those static members are guaranteed to be instantiated before any class is instantiated.
If you need complex logic, do it in a static constructor:
public class MyClass
{
public static int MyInt;
public static MyOtherClass MyOther;
static MyClass()
{
MyInt = 12;
MyOther = new MyOtherClass();
}
}
Edit
Based on your edit, I'd say just assign the values to what they need to be before you instantiate the class, like so:
public class MyClass
{
public static int MyInt;
public static MyOtherClass MyOther;
}
// elsewhere in code, before you instantiate MyClass:
MyClass.MyInt = 12;
MyClass.MyOther = new MyOtherClass();
MyClass myClass = new MyClass();
That said, this method gives you no guarantee that MyInt and MyOther are set before MyClass is instantiated. It will work, but requires discipline before instantiating MyClass.
One alternative pattern you might follow looks like this:
public class MyClass
{
private static int MyInt;
private static MyOtherClass MyOther;
private static bool IsStaticInitialized = false;
public static InitializeStatic(int myInt, MyOtherClass other)
{
MyInt = myInt;
MyOther = other;
IsStaticInitialized = true;
}
public MyClass()
{
if(!IsStaticInitialized)
{
throw new InvalidOperationException("Static Not Initialized");
}
// other constructor logic here.
}
}
// elsewhere in your code:
MyClass.InitializeStatic(12, new MyOtherClass());
MyClass myClass = new MyClass();
// alternatiavely:
MyClass myClass = new MyClass(); // runtime exception.

Categories

Resources