I'm just trying reflection :
using System;
using System.Collections.Generic;
using System.Reflection;
public class CTest {
public string test;
}
public class MyClass
{
public static void Main()
{
CTest cTest = new CTest();
Type t=cTest.GetType();
PropertyInfo p = t.GetProperty("test");
cTest.test = "hello";
//instruction below makes crash
string test = (string)p.GetValue(cTest,null);
Console.WriteLine(cTest.GetType().FullName);
Console.ReadLine();
}
}
"test" is not a property, it's a field. You should use Type.GetField method to get a FieldInfo:
CTest CTest = new CTest();
Type t = CTest.GetType();
FieldInfo p = t.GetField("test");
CTest.test = "hello";
string test = (string)p.GetValue(CTest);
Console.WriteLine(CTest.GetType().FullName);
Console.ReadLine();
Others have observed that the member is a field. IMO, though, the best fix is to make it a property. Unless you're doing some very specific things, touching fields (from outside the class) is usually a bad idea:
public class CTest {
public string test { get; set; }
}
test is not a property, it is a member variable.
using System;
using System.Collections.Generic;
using System.Reflection;
public class CTest {
public string test;
public string test2 {get; set;}
}
public class MyClass
{
public static void Main()
{
CTest CTest = new CTest();
Type t=CTest.GetType();
FieldInfo fieldTest = t.GetField("test");
CTest.test = "hello";
string test = (string)fieldTest.GetValue(CTest);
Console.WriteLine(test);
PropertyInfo p = t.GetProperty("test2");
CTest.test2 = "hello2";
//instruction below makes crash
string test2 = (string)p.GetValue(CTest,null);
Console.WriteLine(test2);
Console.ReadLine();
}
}
Related
Casting does not make copies of objects. More concretely IEnumerable.Cast, according to this resource, which makes total sense. However for this app, find fiddle, reference equals is false if I change the log at the end from the Cast<BaseClass> to Cast<DerivedClass1>. Check logs at the main program.
are equal: True areEqualRef: True areEqualRef: False
Posting the code, just in case, omit it of you get my point playing around with the fiddle :)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp17
{
public class BaseClass {
string name = "I am base";
public Type type;
public enum Type {
a,b,c,d
}
public BaseClass(Type type) {
this.type = type;
}
}
public class DerivedClass1 : BaseClass
{
string name = "I am derivedA";
public DerivedClass1(): base(Type.a) {
}
}
public class DerivedClass2 : BaseClass
{
string name = "I am derivedB";
public DerivedClass2() : base(Type.b)
{
}
}
public class Foo
{
public Dictionary<BaseClass.Type, List<BaseClass>> dict = new Dictionary<BaseClass.Type, List<BaseClass>>();
public Foo() {
dict[BaseClass.Type.a] = new List<BaseClass>();
dict[BaseClass.Type.b] = new List<BaseClass>();
dict[BaseClass.Type.c] = new List<BaseClass>();
dict[BaseClass.Type.d] = new List<BaseClass>();
AddItem(new DerivedClass1());
AddItem(new DerivedClass1());
AddItem(new DerivedClass2());
AddItem(new DerivedClass2());
AddItem(new DerivedClass2());
}
public IEnumerable<T> GetEnumByType<T>(BaseClass.Type type) where T : BaseClass
{
if (dict.ContainsKey(type))
{
if (type == BaseClass.Type.a)
{
Console.WriteLine($"are equal: { object.ReferenceEquals(dict[type].Cast<T>(), dict[BaseClass.Type.a])}");
}
return dict[type].Cast<T>();
}
return null;
}
public void AddItem<T>(T item) where T : BaseClass
{
dict[item.type].Add(item);
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
IEnumerable myList = foo.GetEnumByType<BaseClass>(BaseClass.Type.a);
Console.WriteLine($"areEqualRef: {object.ReferenceEquals(foo.dict[BaseClass.Type.a].Cast<BaseClass>(), foo.dict[BaseClass.Type.a])}");
Console.ReadLine();
}
}
}
Update:
Updated the fiddle with both logs to avoid the need of copy/pasting
You need to notionally separate what is being compared here. When it says that Enumerable.Cast<T> doesn't make copies of objects, it is talking about the individual objects in the sequence. Not the sequence itself. In order to perform the necessary reshaping, the sequence returned from the Cast<T> method is a different wrapper/decorator instance over the original sequence.
Since you're using ReferenceEquals on the sequence, this will report false. However, if you were to compare each object from the sequences (pairwise in turn), you would find that those were the same objects.
I'm trying to simplify code for extracting data from property attribute.
Attribute:
[AttributeUsage(AttributeTargets.Property)]
class NameAttribute : Attribute
{
public string Name { get; }
public ColumnAttribute(string name)
{
Name = name;
}
}
Attribute contents extraction code ( null-checks removed ):
public static string GetName<T>(string propName)
{
var propertyInfo = typeof(T).GetProperty(propName);
var nameAttribute = (NameAttribute)propertyInfo.GetCustomAttributes(typeof(NameAttribute)).FirstOrDefault();
return nameAttribute.Name;
}
Sample class:
class TestClass
{
[Column("SomeName")]
public object NamedProperty { get; set; }
}
Call sample:
var name = GetName<TestClass>(nameof(TestClass.NamedProperty))
Is it any way to rewrite attribute contents extraction method to simplify/shorten its call. It's too inconvenient for me due to its length.
Something like CallerMemberNameAttribute would be great but i found nothing.
Your syntax is already pretty short. The only redundant information is the class name, everything else is needed, it won't get much shorter. You could have a shorter syntax n your call as demonstrated below, where you remove the redundancy of the class name. However, that comes at the cost or a more complex implementation. It's up to you to decide if that's worth it:
namespace ConsoleApp2
{
using System;
using System.Linq.Expressions;
using System.Reflection;
static class Program
{
// your old method:
public static string GetName<T>(string propName)
{
var propertyInfo = typeof(T).GetProperty(propName);
var nameAttribute = propertyInfo.GetCustomAttribute(typeof(NameAttribute)) as NameAttribute;
return nameAttribute.Name;
}
// new syntax method. Still calls your old method under the hood.
public static string GetName<TClass, TProperty>(Expression<Func<TClass, TProperty>> action)
{
MemberExpression expression = action.Body as MemberExpression;
return GetName<TClass>(expression.Member.Name);
}
static void Main()
{
// you had to type "TestClass" twice
var name = GetName<TestClass>(nameof(TestClass.NamedProperty));
// slightly less intuitive, but no redundant information anymore
var name2 = GetName((TestClass x) => x.NamedProperty);
Console.WriteLine(name);
Console.WriteLine(name2);
Console.ReadLine();
}
}
[AttributeUsage(AttributeTargets.Property)]
class NameAttribute : Attribute
{
public string Name { get; }
public NameAttribute(string name)
{
this.Name = name;
}
}
class TestClass
{
[Name("SomeName")]
public object NamedProperty { get; set; }
}
}
The output is the same:
SomeName
SomeName
I'm currently having trouble and I have no clue how to fix it.
I have 2 classes:
class A
{
public string MyParam { get; set; }
}
class B : A
{
public new string MyParam { get { return base.MyParam != null ? base.MyParam.Substring(1) : null; } }
}
When I try to access the B.MyParam it works when I have a the correct type, but in most of my methods I have a generic type
with :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
public class A
{
public string MyParam { get; set; }
}
public class B : A
{
public new string MyParam
{
get { return base.MyParam != null ? base.MyParam.Substring(1) : null; }
}
}
public static void MyMethod<T>(T variable) where T : A
{
Console.WriteLine(variable.MyParam);//this print hello
Console.WriteLine((variable as B).MyParam);//this print ello (exactly what i want)
Console.WriteLine(typeof(T)); // this print ConsoleApplication1.Program+A
Console.WriteLine(variable.GetType()); // this print ConsoleApplication1.Program+B
// so i need something like that
Console.WriteLine((variable as variable.GetType()).MyParam); // this line is invalid
}
static void Main(string[] args)
{
A a = new B();
a.MyParam = "Hello";
Console.WriteLine(a.GetType());
MyMethod(a);
Console.ReadKey();
}
}
}
Is there a way to do it?
Thank you in advance.
EDIT: it seems that what i want is :
dynamic variable2 = Convert.ChangeType(variable, variable.GetType());
Console.WriteLine(variable2.MyParam);
Your code doesn´t make any sense. If A inherits from B you´ll need A to override the base-implementation for your property. So I´ll assume you should rethink your inheritance-chain.
You can use override for this. Thus when your variable-parameter is of your base-class (I renamed that to A) you´re calling the base-method, if it´s a derived instance (here B) you´re calling the override:
class A
{
public virtual string MyParam { get; }
}
class B : A // note here that B derives from A, not the other way round
{
public override string MyParam
{
get { return base.MyParam != null ? base.MyParam.Substring(1) : null; },
set { ... }
}
}
EDIT: While new intrduces a new member which (accidentally) has the same name (and signature) as the base-member it effectivly hides the base-member. Thus you effectivly have two members. Your only way to indicate which member should be used is by casting your instance to the desired class from which you need the implementation. However this somehow breaks the purpose of generics as the generic member has to know the exact types that are possible for the type-parameter.
Anyway this seems like broken design to me, as you´re actually creating a new member which has another meaning. So you should also give it a new name.
Based on your generic method, I think all you need is an interface.
public interface IMyParam
{
string MyParam { get; set; }
}
Your classes.
class A : IMyParam
{
public virtual string MyParam { get; set; }
}
class B : A
{
public override string MyParam
{
get { return base.MyParam != null ? base.MyParam.Substring(1) : null; }
}
}
And your method, won't need to be generic.
public void MyMethod(IMyParam variable)
{
// Your logic here, for example.
Console.WriteLine(variable.MyParam);
}
Calling your method.
A a = new A();
a.MyParam = "Hello";
B b = new B();
b.MyParam = "Hello";
A ab = new B();
ab.MyParam = "Hello";
MyMethod(a); // Prints Hello
MyMethod(b); // Prints ello
MyMethod(ab); // Prints ello
This has been driving me mad for a while now. I have a class which contains other classes. I need to loop through the first class looking for typeof second class then retreive the value of the fields.
the below code obviously fails on the line
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
as this isn't a valid field. Possibly I'm going about this the wrong way - any ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
MyFirstClass mFC = new MyFirstClass();
FieldInfo[] fI = mFC.GetType().GetFields();
foreach (FieldInfo field in fI)
{
if (field.FieldType.Name == "MySecondClass")
{
//get the fields
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
}
}
}
}
class MyFirstClass
{
public MySecondClass firstMSC = new MySecondClass("First Instance");
public MySecondClass secondMSC = new MySecondClass("Second Instance");
public string firstClassString = "I'm from the first class";
public int firstClassInt = 5;
}
class MySecondClass
{
public MySecondClass(string input)
{
this.secondClassString = input;
}
public string secondClassString;
public int secondClassInt = 10;
}
}
field.GetValue accepts the instance from which it gets the field value.
In your case I would expect it should be field.GetValue(mFC).
Also field.FieldType.Name == "MySecondClass" is not the best way to check the type as type name change will cause code to break. I recommend replacing it with field.FieldType == typeof(MySecondClass).
((MySecondClass)field.GetValue(mFC)).secondClassString;
use this inside console.writeline
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List list = new List();
list.Add(new A());
var list2 =
from p in list
select p as B;
Console.WriteLine(list2.First().myString);
Console.ReadLine();
}
}
class A
{
public string myString = "abc";
}
class B : A
{
}
}
How can I solve this?
Thanks
You can't do that; the list contains an instance of A, you can't cast A to B. You can only cast "upwards" in the inheritance chain, not downwards. So if you change places on A and B in your code, it works:
class Program
{
static void Main(string[] args)
{
List<B> list = new List<B>();
list.Add(new B());
var list2 =
from p in list
select p as A;
Console.WriteLine(list2.First().myString);
Console.ReadLine();
}
}
class A
{
public string myString = "abc";
}
class B : A { }
If you want to convert in the other direction, you need to write code for the conversion:
class Program
{
static void Main(string[] args)
{
List<A> list = new List<A>();
list.Add(new B());
var list2 = list.ConvertAll<B>(a => B.FromA(a));
Console.WriteLine(list2.First().myString);
Console.ReadLine();
}
}
class A
{
public string myString = "abc";
}
class B : A
{
public B() { }
public static B FromA(A fromInstance)
{
B result = new B();
result.myString = fromInstance.myString;
return result;
}
}
list2.First().myString will try to access myString on a null reference. The as operator returns null if you can't cast. And object-oriented design principles tell us that you can use a subclass in any place where you can also use its superclass but not the other way around. So you're filling your list with instances of A and try to cast them to B. But they simply aren't instances of B so that cast will always fail (and, since you're using as, return null).
Your program does "convert father class to son class", contrary to your question title. Anyway, that can't be done.
To clarify this:
Try changing class B to the following:
class B : A
{
public string MyStringB { get; set; }
}
If you were able to cast A to B, what would the myStringB value be since it was never defined on A?
Create a constructor in B class which takes an instance of A class.
You can create a copy constructor which takes an object of type A:
class B : A
{
public B(A copy) {
myString = copy.myString;
}
}
I'm not too familiar with LINQ, however, so I'm not sure how you'd get it to automatically use this.