This question already has answers here:
Get value of a public static field via reflection
(4 answers)
Closed 1 year ago.
How can i get the public properties from a static instance of a class?
Example
public record MyClass{
public static MyClass Instance1 = new(true);
public static MyClass Instance2 = new(false);
public bool MyParam {get;init;}
private MyClass(bool myParam){
MyParam = myParam;
}
}
And I would like to access the value of MyParam from the static instances Instance1, Instance2.
Edit: sorry for the bad details. I want to do this all via reflection. Get all the static instances of the class, and for each instance the value of the param.
Based on how you wrote your code, you can accessit as MyClass.Instance1.MyParam
For example (Try it out here: https://dotnetfiddle.net/nwBbkH#)
using System;
public class Program
{
public static void Main()
{
// Here we are accessing MyParam
Console.WriteLine(MyClass.Instance1.MyParam);
Console.WriteLine(MyClass.Instance2.MyParam);
}
}
public record MyClass
{
public static MyClass Instance1 = new(true);
public static MyClass Instance2 = new(false);
public bool MyParam
{
get;
init;
}
private MyClass(bool myParam)
{
MyParam = myParam;
}
}
Related
This question already has answers here:
.NET Attributes: Why does GetCustomAttributes() make a new attribute instance every time?
(3 answers)
Closed 2 years ago.
Shouldn't PropertyInfo.GetCustomAttribute(s) return the same instance of Attribute? The following code appears it returns different instances:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Reflection;
namespace AttributeNoShared
{
[TestClass]
public class UnitTest1
{
private sealed class AnyAttribute : Attribute
{
}
private sealed class AnyClass
{
[Any]
public int AnyProperty { get; set; }
}
[TestMethod]
public void TestMethod1()
{
var propertyInfo = typeof(AnyClass).GetProperty(nameof(AnyClass.AnyProperty));
var result1 = propertyInfo.GetCustomAttribute<AnyAttribute>();
var result2 = propertyInfo.GetCustomAttribute<AnyAttribute>();
Assert.AreEqual(result1, result2); // This succeeded
Assert.IsTrue(object.ReferenceEquals(result1, result2), "Different instance of attribute"); // This failed
}
}
}
Is this a bug? I'm expecting runtime Attribute to be shared because I would like to store some state in it.
No, it's not an error, that's by dessign. Attributes aren't instanced until they are requested. In order to return the same instance .net would need to create a cache for the attributes and that could lead to consume too much memory in some scenerios as these would need to be preserve during all the life of the process.
Anyways, you can always create static properties that are shared by all the instances. If you thought that there would be one instance of the attribute per each tagged property you can do something like this:
public class InformationAttribute : Attribute
{
static Dictionary<string, object> storage = new Dictionary<string, object>();
string propName;
public InformationAttribute(string PropertyName)
{
propName = PropertyName;
}
public void SetValue(object Value)
{
storage[propName] = Value;
}
public object GetValue()
{
if(storage.ContainsKey(propName))
return storage[propName];
return null;
}
}
and use like this:
private sealed class AnyClass
{
[Information("AnyClass.AnyProperty")]
public int AnyProperty { get; set; }
}
//...
var propertyInfo = typeof(AnyClass).GetProperty(nameof(AnyClass.AnyProperty));
var result = propertyInfo.GetCustomAttribute<AnyAttribute>();
if(result.GetValue() == null)
result.SetValue(WhatEverYouWantToStore);
This question already has answers here:
A field initializer cannot reference the nonstatic field, method, or property - while creating a list
(2 answers)
Error 1 A field initializer cannot reference the non-static field, method, or property
(2 answers)
Closed 4 years ago.
In java I can do this
public class HelloWorld
{
public static void main(String[] args)
{
OtherClass oc = new OtherClass();
oc.a.run();
}
}
public class OtherClass
{
public int s = 3;
public Runnable a = () -> System.out.println("s is " + s);
}
The output will be s is 3. When I try this in C# with this code
using System;
namespace SomeNamespace
{
public class Program
{
public static void Main(string[] args)
{
MyClass m = new MyClass();
m.a.Invoke();
}
}
public class MyClass
{
public int s = 3;
public Action a = () => Console.WriteLine(s);
}
}
Then I get (23:51) A field initializer cannot reference the non-static field, method, or property 'SomeNamespace.MyClass.s'
//Program.cs
public interface TestVal
{
//Input Param
string Input { get; }
//will return output
TestValRes ValidateRe(string input);
}
class MyClass : ITestVal
{
static void Main(string[] args)
{
var instance = new MyClass();
instance.Run();
}
public void Run()
{
ValidateRe("test");
}
public ITestValRes ValidateRe(string input)
{
return null; // return an instance of a class implementing ITestValRes here.
}
}
//TestvalRes.cs
public interface TestvalRes
{
string Input { get; }
bool IsValid { get; }
}
So I just want to pass a string to the TestVal, do validation and call TestvalRes to return whether it is Valid or not, and if Invalid, why? So the validation will be done in the first public interface - TestVal, however I still need to call it inside the Main(), right?
First off, I'd recommend following C# naming conventions and name your interfaces ITestVal and ITestValRes respectively.
Next, static method cannot call instance methods in the same class (without creating an instance and using that). You need to create an instance of the class and pass control of the application flow to that:
class MyClass : ITestVal
{
static void Main(string[] args)
{
var instance = new MyClass();
instance.Run();
}
public void Run()
{
ValidateRe("test");
}
public ITestValRes ValidateRe(string input)
{
return null; // return an instance of a class implementing ITestValRes here.
}
}
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.
Without any code in the subclasses, I'd like an abstract class to have a different copy of a static variable for each subclass. In C#
abstract class ClassA
{
static string theValue;
// just to demonstrate
public string GetValue()
{
return theValue;
}
...
}
class ClassB : ClassA { }
class ClassC : ClassA { }
and (for example):
(new ClassB()).GetValue(); // returns "Banana"
(new ClassC()).GetValue(); // returns "Coconut"
My current solution is this:
abstract class ClassA
{
static Dictionary<Type, string> theValue;
public string GetValue()
{
return theValue[this.GetType()];
}
...
}
While this works fine, I'm wondering if there's a more elegant or built-in way of doing this?
This is similar to Can I have different copies of a static variable for each different type of inheriting class, but I have no control over the subclasses
There is a more elegant way. You can exploit the fact that statics in a generic base class are different for each derived class of a different type
public abstract class BaseClass<T> where T : class
{
public static int x = 6;
public int MyProperty { get => x; set => x = value; }
}
For each child class, the static int x will be unique for each unique T
Lets derive two child classes, and we use the name of the child class as the generic T in the base class.
public class ChildA: BaseClass<ChildA>
{
}
public class ChildB : BaseClass<ChildB>
{
}
Now the static MyProperty is unique for both ChildA and ChildB
var TA = new ChildA();
TA.MyProperty = 8;
var TB = new ChildB();
TB.MyProperty = 4;
While this works fine, I'm wondering if there's a more elegant or built-in way of doing this?
There isn't really a built-in way of doing this, as you're kind of violating basic OO principles here. Your base class should have no knowledge of subclasses in traditional object oriented theory.
That being said, if you must do this, your implementation is probably about as good as you're going to get, unless you can add some other info to the subclasses directly. If you need to control this, and you can't change subclasses, this will probably be your best approach.
This is a little different than what you're asking for, but perhaps accomplishes the same thing.
class Program
{
static void Main(string[] args)
{
Console.WriteLine((new B()).theValue);
Console.WriteLine((new C()).theValue);
Console.ReadKey();
}
}
public abstract class A
{
public readonly string theValue;
protected A(string s)
{
theValue = s;
}
}
public class B : A
{
public B(): base("Banana")
{
}
}
public class C : A
{
public C(): base("Coconut")
{
}
}
There's an alternative solution which might or might not be better than yours, depending on the use case:
abstract class ClassA
{
private static class InternalClass<T> {
public static string Value;
}
public string GetValue()
{
return (string)typeof(InternalClass<>)
.MakeGenericType(GetType())
.GetField("Value", BindingFlags.Public | BindingFlags.Static)
.GetValue(null);
}
}
This approach is used in EqualityComparer<T>.Default. Of course, it's not used for this problem. You should really consider making GetValue abstract and override it in each derived class.
What about this?
class Base {
protected static SomeObjectType myVariable;
protected void doSomething()
{
Console.WriteLine( myVariable.SomeProperty );
}
}
class AAA : Base
{
static AAA()
{
myVariable = new SomeObjectType();
myVariable.SomeProperty = "A";
}
}
class BBB : Base
{
static BBB()
{
myVariable = new SomeObjectType();
myVariable.SomeProperty = "B";
}
}
It works for me.
Would be even nicer with Interface.
Simple solution: just use word "new".
public abstract class AbstractClass
{
public static int Variable;
}
public class RealizationA : AbstractClass
{
public new static int Variable;
}
public class RealizationB : AbstractClass
{
public new static int Variable;
}
And the result:
AbstractClass.Variable = 1;
RealizationA.Variable = 2;
RealizationB.Variable = 3;
Console.WriteLine(AbstractClass.Variable); //1
Console.WriteLine(RealizationA.Variable); //2
Console.WriteLine(RealizationB.Variable); //3
or you can use property:
//in abstract class
public static int Variable {get; set;}
//in child class
public static new int Variable {get; set;}
or function (but remember to add "new" to both variable and function):
//in abstract class
protected static int Variable;
public static int GetVariable() { return Variable; }
public static void SetVariable(int v) { Variable = v; }
//in child class
protected new static int Variable;
public static new int GetVariable() { return Variable; }
public static new void SetVariable(int v) { Variable = v; }
or you can use private variables (you don't need to use "new") with functions to get and set:
//in abstract class
private static int Variable;
//get and set methods
//in child class
private static int Variable;
//get and set methods