Say I have a class declared as follows:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass()
{
}
public void FuncA(int n)
{
//irrelevant code here
}
public void FuncB(int n)
{
//other irrelevant code here
}
}
I want to be able to use this class like this
ExampleClass excl = new ExampleClass() { Do = FuncA }
or
ExampleClass excl = new ExampleClass() { Do = excl.FuncA }
or
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }
I can compile the second option there, but I get a "Delegate to an instance method cannot have null 'this'." exception when I hit that code. The third one doesn't even make sense, because FuncA isn't static.
In my actual code, there will be maybe 10-15 different functions it could get tied to, and I could be adding or removing them at any time, so I don't want to have to have a large switch or it-else statement. Additionally, being able assign a value to 'Do' when instantiating the class is very convenient.
Am I just using incorrect syntax? Is there a better way to create a class and assign an action in one line? Should I just man up and manage a huge switch statement?
You have to create the instance of the class and later set the property to the instance member. Something like:
ExampleClass excl = new ExampleClass();
excl.Do = excl.FuncA;
For your line:
ExampleClass excl = new ExampleClass() { Do = FuncA }
FuncA is not visible without an instance of the class.
For:
ExampleClass excl = new ExampleClass() { Do = excl.FuncA }
Instance has not yet been created that is why you are getting the exception for null reference.
For:
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }
FuncA is not a static method, you can't access it with the class name.
In object initializer syntax you cannot access the variable being initialized before it is definitely assigned:
ExampleClass excl = new ExampleClass()
{
Do = excl.FuncA //excl is unavailable here
}
Read Object and Collection Initializers (C# Programming Guide) for more info.
You could do the following, for example:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass(bool useA)
{
if (useA)
Do = FuncA;
else
Do = FuncB;
}
public void FuncA(int n)
{
//irrelevant code here
}
public void FuncB(int n)
{
//other irrelevant code here
}
}
and use it:
ExampleClass exclA = new ExampleClass(true);
ExampleClass exclB = new ExampleClass(false);
Another idea is if these functions may be declared as static (i.e. they don't need any instance members of the ExampleClass), then this would work:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass() { }
public static void FuncA(int n) { /*...*/}
public static void FuncB(int n) { /*...*/}
}
and use it the way you want:
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA };
If you have extension methods make sure that those values are not null before invoking the extension methods or handle nulls inside the extension methods.
For example
public static ExtensionClass
{
public static bool RunExtensionMethod(this object myObject)
{
var someExecutionOnMyObject = myObject.IsValid();
//the above line would invoke the exception when myObject is null
return someExecutionOnMyObject ;
}
}
public void CallingMethod()
{
var myObject = getMyObject();
if(myObject.RunExtensionMethod()) //This would cause "delete to an instance method cannot have null" if myObject is null
{
}
}
To handle this scenario handle nulls and assert nulls if you own the extension class.
public static ExtensionClass
{
public static bool RunExtensionMethod(this object myObject)
{
if(myObject == null) throw new ArgumentNullException(nameof(myObject));
var someExecutionOnMyObject = myObject.IsValid();
return someExecutionOnMyObject ;
}
}
public void CallingMethod()
{
var myObject = getMyObject();
if(myObject != null && myObject.RunExtensionMethod())
{
}
}
Related
Hello I am working on a objectpooling class has T "ObjectPooling".
And made a child class. So I want to make automatic singleton for this class. So if I use "instance" it should check if m_instance is null. If yes "spawn" the script and assign m_instance.
public abstract class ObjectPooling<T> : MonoBehaviour
{
public static float start = 30;
public static bool extendable = true;
public List<T> objects = new List<T>();
public abstract T getNext();
public abstract void Add(T obj);
static T m_instance;
public static T instance
{
get
{
return m_instance ?? (m_instance = CreateInstance());
}
}
protected static T CreateInstance()
{
GameObject g = new GameObject("ObjectPooling");
var c = g.AddComponent<T>();
return c;
}
}
The problem is at the last lines in the CreateInstance().
It says
An implicitly typed local variable declaration cannot be initialized
with `UnityEngine.GameObject.AddComponent(System.Type)'
I am not sure what can I do here now. I tried with ObjectPooling before but thats gives no error but also is not working.
So my goal is that the child has also singleton. I did it currently manually but want I want to later should be like this (ofc the base class should do it instead of child class but still check it).
public class BulletPooling : ObjectPooling<BulletBase>
{
public override void Add(BulletBase obj)
{
if(extendable)
objects.Add(obj);
}
public override BulletBase getNext()
{
for(int i = 0; i < objects.Count; i++)
{
var bs = objects[i];
if (!bs.gameObject.activeInHierarchy)
return bs;
}
return null;
}
// this part
static BulletPooling m_instance;
public static BulletPooling instance
{
get
{
return m_instance ?? (m_instance = CreateInstance());
}
}
protected static BulletPooling CreateInstance()
{
GameObject g = new GameObject("ObjectPooling");
var c = g.AddComponent<BulletPooling>();
return c;
}
}
You can see here I am working with new Childclass which has T = BulletBase
This is because GameObject.AddComponent requires an object of a specific type, rather than "any type". In your ObjectPooling class, you only specify that it can be an object of any type, and the compiler cannot infer which types you are using beforehand.
AddComponent is kind of a nasty function, since you can also pass it a string, which should be the name of a script class.
You could specify the type that T must adhere to as UnityEngine.Component to get around this. that would look like this :
public abstract class ObjectPooling<T>: MonoBehaviour where T : UnityEngine.Component
{
public static float start = 30;
public static bool extendable = true;
public List<T> objects = new List<T>();
public abstract T getNext();
public abstract void Add(T obj);
static T m_instance;
public static T instance
{
get
{
return m_instance ?? (m_instance = CreateInstance());
}
}
protected static T CreateInstance()
{
GameObject g = new GameObject("ObjectPooling");
//this is where your compiler could not tell if T was the correct type by the way...
var c = g.AddComponent<T>();
return c;
}
}
but that might break the functionality of adding scripts as game components using a string with their name. (though i think in your case, it won't be a problem)
See the code below. I want a class that automatically enumerates all the defined static readonly instances of its own type (see TestClass as an example, it defines 3 static readonly instances of its own type).
I want this automation because I want to loop over the defined types and not risk the change of forgetting to add a new instance to the list of All.
Ok, I have it working, that is not the point. But why doesn't FillAll work when called from a static constructor? See the commented static constructor in DefinedInstancesBase<T> code. I mean FieldInfo.GetValue(null) returns null in the static constructor, though the debugger has already hit creating the static readonly instances before the FieldInfo.GetValue(null) is called.
I'm very curious why it doesn't work. Is this by design?
public abstract class DefinedInstancesBase<T>
{
public static IList<T> All
{
get
{
if (_All == null)
{
FillAll();
}
return _All;
}
}
//Why this doesn't work? No idea.
//static DefinedInstancesBase()
//{
// FillAll();
//}
private static void FillAll()
{
var typeOfT = typeof(T);
var fields = typeOfT.GetFields(BindingFlags.Public | BindingFlags.Static);
var fieldsOfTypeT = fields.Where(f => f.FieldType == typeOfT);
_All = new List<T>();
foreach (var fieldOfTypeT in fieldsOfTypeT)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
private static List<T> _All = null;
}
[TestClass]
public class DefinedInstancesTest
{
[TestMethod]
public void StaticReadOnlyInstancesAreEnumerated()
{
//Given
var expectedClasses = new List<TestClass>
{
TestClass.First,
TestClass.Second,
TestClass.Third,
};
//When
var actualClasses = TestClass.All;
//Then
for (var i=0; i<expectedClasses.Count; i++)
{
Assert.AreEqual(expectedClasses[i].Id, actualClasses[i].Id);
}
}
private class TestClass : DefinedInstancesBase<TestClass>
{
public static readonly TestClass First = new TestClass(1);
public static readonly TestClass Second = new TestClass(2);
public static readonly TestClass Third = new TestClass(3);
public int Id { get; private set; }
private TestClass(int pId)
{
Id = pId;
}
}
}
There are two separate issues at work here.
There is a typo in your static constructor in the code above. Try changing static DefinedInstances() to static DefinedInstancesBase(), because currently it is just specified as a private static function.
The second and more important issue is to understand the order that the various constructors are being called in. What is happening is that the static constructor on the base abstract class is getting triggered by the instantiation (during member initializer) of the First field in the derived class. Therefore, First is still null when the static constructor of DefinedInstancesBase class is being called (and thus the FindAll() method).
See the following code (slightly modified to better illustrate the issue) and output:
public void Main()
{
DefinedInstancesTest dit = new DefinedInstancesTest();
dit.StaticReadOnlyInstancesAreEnumerated();
}
public abstract class DefinedInstancesBase<T>
{
public static IList<T> All
{
get
{
//if (_All == null)
// FillAll();
return _All;
}
}
// correctly named static ctor
static DefinedInstancesBase() { FillAll(); }
private static void FillAll()
{
Console.WriteLine("FillAll() called...");
var typeOfT = typeof(T);
var fields = typeOfT.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var fieldsOfTypeT = fields.Where(f => f.FieldType == typeOfT);
_All = new List<T>();
foreach (var fieldOfTypeT in fieldsOfTypeT)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
private static List<T> _All = null;
}
//[TestClass]
public class DefinedInstancesTest
{
//[TestMethod]
public void StaticReadOnlyInstancesAreEnumerated()
{
//Given
var expectedClasses = new List<TestClass>
{
TestClass.First,
TestClass.Second,
TestClass.Third,
};
//When
var actualClasses = TestClass.All;
//Then
for (var i=0; i<expectedClasses.Count; i++)
{
//Assert.AreEqual(expectedClasses[i].Id, actualClasses[i].Id);
if (expectedClasses[i].Id != actualClasses[i].Id)
Console.WriteLine("not equal!");
}
}
private class TestClass : DefinedInstancesBase<TestClass>
{
public static readonly TestClass First;
public static readonly TestClass Second;
public static readonly TestClass Third;
public int Id { get; private set; }
static TestClass()
{
Console.WriteLine("TestClass() static ctor called...");
First = new TestClass(1);
Second = new TestClass(2);
Third = new TestClass(3);
}
private TestClass(int pId)
{
Console.WriteLine("TestClass({0}) instance ctor called...", pId);
Id = pId;
}
}
}
TestClass() static ctor called...
// the line "First = new TestClass(1);" now triggers the base class static ctor to be called,
// but the fields First, Second, and Third are all still equal to null at this point!
FillAll() called...
TestClass(1) instance ctor called...
TestClass(2) instance ctor called...
TestClass(3) instance ctor called...
// this null reference exception to be expected because the field value actually was null when FindAll() added it to the list
Unhandled Expecption:
System.NullReferenceException: Object reference not set to an instance of an object.
I have an object that only initializes itself with barebones data when constructed (fast), and loads itself for real (slow) when first accessed. The idea is that I'm creating a lot of these barebones objects at startup and hash them into a map, then fully load each object whenever it is individually accessed for the first time. The problem is that I cannot guarantee how clients will interact with this object, there are multiple public methods that might be invoked.
Is there a good pattern to support this kind of situation? The obvious (and my current) solution is to track state with an internal bool, check against that bool in every function that might be invoked, and load that way. But that requires code duplication of that behavior across all public functions, and is vulnerable to errors.
I can imagine a single point-of-entry method that then dishes out behaviors based on a client request type etc., but before I go consider going down that road I want to see if there's a commonly accepted approach/pattern that I might not be aware of. I'm doing this in C#, but any insight is appreciated.
If I understood what you want to achieve, you are looking for the Proxy Design Pattern, more specifically, a virtual Proxy.
Refer to http://www.dofactory.com/net/proxy-design-pattern
A small example would be something like:
public abstract class IObjectProvider
{
public abstract IObjectProvider Object{get;}
public abstract void doStuff();
}
public class RealObject : IObjectProvider
{
public RealObject()
{
//Do very complicated and time taking stuff;
}
public override IObjectProvider Object
{
get { return this; }
}
public override void doStuff()
{
//do this stuff that these objects normally do
}
}
public class ObjectProxy : IObjectProvider
{
private IObjectProvider objectInstance = null;
public override IObjectProvider Object
{
get
{
if (objectInstance == null)
objectInstance = new RealObject();
return objectInstance;
}
}
public override void doStuff()
{
if(objectInstance!=null)
objectInstance.doStuff();
}
}
public class SkeletonClass
{
public IObjectProvider Proxy1 = new ObjectProxy();
public IObjectProvider Proxy2 = new ObjectProxy();
}
static void Main(String[] args)
{
//Objects Not Loaded
SkeletonClass skeleton = new SkeletonClass();
//Proxy1 loads object1 on demand
skeleton.Proxy1.Object.doStuff();
//Proxy2 not loaded object2 until someone needs it
}
Here's an example of dynamic proxy approach.
using System;
using System.Diagnostics;
using Castle.DynamicProxy; //Remember to include a reference, too. It's nugettable package is Castle.Core
namespace ConsoleApp
{
public class ActualClass
{
//Have static instances of two below for performance
private static ProxyGenerator pg = new ProxyGenerator();
private static ActualClassInterceptor interceptor = new ActualClassInterceptor();
//This is how we get ActualClass items that are wrapped in the Dynamic Proxy
public static ActualClass getActualClassInstance()
{
ActualClass instance = new ActualClass();
return pg.CreateClassProxyWithTarget<ActualClass>(instance, interceptor);
}
//Tracking whether init has been called
private bool initialized = false;
//Will be used as evidence of true initialization, i.e. no longer null
private int? someValue = null;
public void Initialize()
{
if (!initialized)
{
//do some initialization here.
someValue = -1; //Will only get set to non-null if we've run this line.
initialized = true;
}
}
//Any methods you want to intercept need to be virtual!
public virtual int replaceValue(int value)
{
//below will blow up, if someValue has not been set to -1 via Initialize();
int oldValue = someValue.Value;
someValue = value;
return oldValue;
}
//block off constructor from public to enforce use of getActualClassInstance
protected ActualClass() { }
}
public class ActualClassInterceptor : ActualClass, IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Call initialize before proceeding to call the intercepted method
//Worth noting that this is the only place we actually call Initialize()
((ActualClass)invocation.InvocationTarget).Initialize();
invocation.Proceed();
}
}
class Program
{
static void Main(string[] args)
{
ActualClass instance1 = ActualClass.getActualClassInstance();
ActualClass instance2 = ActualClass.getActualClassInstance();
int x1 = instance1.replaceValue(41);
int x2 = instance2.replaceValue(42);
int y1 = instance1.replaceValue(82);
Debug.Assert(y1 == 41);
int y2 = instance2.replaceValue(84);
Debug.Assert(y2 == 42);
var read = Console.ReadKey();
}
}
}
I have the following classes, and when I call CreateQuerySettings on the BaseScriptConfigurationList, it returns the new QuerySettings from ConfigurationList, rather than the HierarchicalQuerySettings value in BaseScriptConfigurationList:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
_BaseScriptPageListWatcher = new ConfigurationList<BaseScriptPageConfiguration, BaseScriptPageConfiguration.Property>.
ConfigurationWatcher(null);
_ConfigurationWatcher.ChildWatchers.Add(_BaseScriptPageListWatcher);
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
Edit: I make the call from another class where TConfigurationObjectList is BaseScriptConfigurationList. I've added the constructor to the code above so you can see what it's doing. Please note that EditableConfigurationList inherits from ConfigurationList.
TConfigurationObjectList cl = (TConfigurationObjectList)typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var querySettings = cl.CreateQuerySettings();
When I make this call, it goes into the ConfigurationList.CreateQuerySettings method.
How can I hide the CreateQuerySettings method, so that when I call it from the BaseScriptConfigurationList class, I get a HierarchicalQuerySettings object?
The new modifier can be beasty. Note that you are hiding and not overriding in your example. You are not showing that part of the code, but I assume you have this situation:
class Base
{
public static void BaseMethod() { Console.WriteLine("BASE!"); }
}
class Derived : Base
{
// Hides Base.BaseMethod()
new public static void BaseMethod() { Console.WriteLine("DERIVED!"); }
}
Base a = new Base();
a.BaseMethod(); // -> "BASE!"
Base b = new Derived();
b.BaseMethod(); // -> "BASE!"
Derived b = new Derived();
b.BaseMethod(); // -> "DERIVED!"
In BaseScriptConfigurationList.CreateQuerySettings()
you're return type is QuerySettings<T,T> so you will always get that type as a return value, but you are returning a HierarchicalQuerySettings. You can one, change the return type of CreateQuerySettings() to HierarchicalQuerySettings or two, cast the object to its child type "HierarchicalQuerySettings". If you really want to hide it, you can do this:
public class newclass : BaseScriptConfigurationList
{
public new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return (HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>)base.CreateQuerySettings();
}
}
But that doesn't really seem efficient and i advise against it. Like i said, i maybe missing some other requirement, but based on the info that you gave..
Basically, what I'm seeing (and making assumptions) that TConfigurationObjectList Inhertis from ConfigurationList somewhere along the lines, so on and so forth, all the way up to EditableConfigurationList. since you are dynamically creating an instance of the class TConfigurationObjectList, and calling the method from that point, you will be calling the base ConfigurationList member CreateQuerySettings. You do not have access to the new CreateQuerySettings. If you are creating the class BaseScriptConfigurationList instance at this point, cast the object ((BaseScriptConfigurationList)cl).CreateQuerySettings(). That being said. if you do not know what you have at runtime:
var obj = typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var cl = (obj as BaseScriptConfigurationList) ?? (TConfigurationObjectList)obj;
// or do something else
var querySettings = cl.CreateQuerySettings();
Note i am assuming your architecture is roughly set up like this:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class TConfigurationObjectList : ConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class EditableConfigurationList<T, T1> : TConfigurationObjectList
{
protected EditableConfigurationList(ConfigurationManager configurationManager, object baseScript)
{
throw new NotImplementedException();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
public class QuerySettings<T, T1>
{
}
public class HierarchicalQuerySettings<T, T1, T2> : QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class BaseScriptQueryChildrenSettings
{
}
public class BaseScriptPageConfiguration
{
public class Property
{
}
}
public class InternalAdminObjectType
{
public static object BaseScript { get; set; }
}
public class ConfigurationManager
{
}
public class BaseScriptConfiguration
{
public class Property
{
}
}
Create a base interface for the ConfigurationList class (say IConfigurationList) and use this interface as the data type for the variable cl instead of TConfigurationList.
I have a static Class and within it I have multiple public static attributes. I treat this class as my global class.
However now I need to treat this class as a variable so that I can pass it to a method of another class for processing..
I can't instantiate this class.. So in effect I can only assign the variables inside this class.
Is my understanding correct or am I missing something?
public static class Global
{
public const int RobotMax = 2;
// GUI sync context
public static MainForm mainForm;
public static SynchronizationContext UIContext;
// Database
public static Database DB = null;
public static string localDBName = "local.db";
public static Database localDB = null;
public static Database ChangeLogDB = null;
public static string changeLogDBName = "ChangeLog.db";
}
Let say I have a class like this, and I need to somehow keep a copy of this in another class maybe
public static class Global_bk
{
public const int RobotMax = 2;
// GUI sync context
public static MainForm mainForm;
public static SynchronizationContext UIContext;
// Database
public static Database DB = null;
public static string localDBName = "local.db";
public static Database localDB = null;
public static Database ChangeLogDB = null;
public static string changeLogDBName = "ChangeLog.db";
}
I need to copy the contents from Global to Global_bk.
And after that I need to compare the contents of the two classes in a method like
static class extentions
{
public static List<Variance> DetailedCompare<T>(T val1, T val2)
{
List<Variance> variances = new List<Variance>();
FieldInfo[] fi = val1.GetType().GetFields();
foreach (FieldInfo f in fi)
{
Variance v = new Variance();
v.Prop = f.Name;
v.valA = f.GetValue(val1);
v.valB = f.GetValue(val2);
if (!v.valA.Equals(v.valB))
variances.Add(v);
}
return variances;
}
}
class Variance
{
string _prop;
public string Prop
{
get { return _prop; }
set { _prop = value; }
}
object _valA;
public object valA
{
get { return _valA; }
set { _valA = value; }
}
object _valB;
public object valB
{
get { return _valB; }
set { _valB = value; }
}
}
So on my main form, how do I go about calling the compare method and passing the static Global class inside?
example: extentions.DetailedCompare(Global, Global_bk) ? Of course this would give me an error because I cant pass a type as a variable.
Please help me, this is driving me nuts...
How about the singleton pattern ? You can pass reference to shared interface (IDoable in exable below) and still have just one instance.
I.E.:
public interface IDoable {
int Value { get; set; }
void Foo();
}
public static class DoableWrapper {
private MyDoable : IDoable {
public int Value { get;set; }
public void Foo() {
}
}
private static IDoable s_Doable = new MyDoable();
public static IDoable Instance {
get { return s_Doable; }
}
}
Singleton is the way to go here. You can do it like this:
internal class SomeClass
{
private static SomeClass singleton;
private SomeClass(){} //yes: private constructor
public static SomeClass GetInstance()
{
return singleton ?? new SomeClass();
}
public int SomeProperty {get;set;}
public void SomeMethod()
{
//do something
}
}
The GetInstance Method will return you a SomeClass object that you can edit and pass into whatever you need.
You can access the members with classname.membername.
internal static class SomeClass
{
public static int SomeProperty {get;set;}
public static void SomeMethod()
{
//do something
}
}
static void main()
{
SomeClass.SomeProperty = 15;
SomeClass.SomeMethod();
}
The only way you are going to obtain a variable with the "class" information is using reflection. You can get a Type object for the class.
namespace Foo {
public class Bar
{
}
}
Type type = Type.GetType("Foo.Bar");
Otherwise, if you are really describing a class "instance" then use an object and simply instantiate one.
C# offers no other notation for class variables.