假设我有一个学生类,它包含一个私有成员 StudentID。现在我在另一个类中创建了一个 Student 类的对象,我的要求是更改 StudentID 的值。是否可以访问 StudentID 并更改其值?
10 回答
简而言之:没有。
在长:取决于。
您可以通过属性公开私有字段
private int _studentID;
public int StudentID
{
get { return _studentID; }
set { _studentID = value; }
}
但不知何故,我认为这不是你所追求的。
私有字段是私有的,如果您不希望它是私有的,那么就不要让它私有,或者通过如上所示的属性公开它。
如果您确实需要访问私有字段并设置其值,那么您可以采用反射路线:
var a = new abc();
a.GetType().GetField("x",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(a, 12);
您获取类型,然后使用 Instance 和 NonPublic 字段提取字段,然后设置值。
所以:
public sealed class SomeClass
{
private int _studentID = 0;
public int StudentID
{
get
{
return _studentID;
}
set
{
_studentID = value;
}
}
}
将是“正确”的方式,但使用反射你可以做到
var someclass = new SomeClass();
someclass.GetType()
.GetField("_studentID",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.SetValue(someclass, 12);
如果你想使用反射,那么你可以使用扩展方法助手:
public static class FieldExtensions
{
public static void SetPrivateField<T>(this T instance, string field, object value)
{
typeof(T).GetField(field, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.SetValue(instance, value);
}
}
然后使用该扩展方法,您可以在任何对象上设置任何私有字段!
var someclass = new SomeClass();
someclass.SetPrivateField("_studentID", 12);
您可以制作访问私有成员值的类的Public
属性Student
_StudentId
public class Student
{
private int _StudentId;
public int StudentId
{
get
{
return _StudentId;
}
set
{
_StudentId = value;
}
}
}
现在你可以像这样使用它
Student objStudent = new Student();
objStudent.StudentId = 5; // your Id
您可以使用反射来更改私有成员,但这可能不是您想要的。
如果您不想让成员公开,您可以创建一个更改它的公共方法:
public class Student {
private int StudentID;
public void SetStudentId(int id) {
StudentID = id;
}
}
如果不希望公共方法易于访问,可以为它制作一个接口,并专门实现该接口。这样,该方法仅在您具有接口类型的引用时可用,而不是在您具有类类型的引用时可用:
public interface IChangeId {
public void SetStudentId(int id);
}
public class Student : IChangeId {
private int StudentID;
void IChangeId.SetStudentId(int id) {
StudentID = id;
}
}
例子:
Student john = new Student();
john.SetStudentId(42); // not allowed
IChangeId johnSetId = john;
johnSetId.SetStudentId(42); // allowed
不,你不能。您需要有一个访问学生 ID 私有成员的公共属性,或者您可以使用一些公共方法访问它。
也许在构造函数中传递 ID 值是有意义的,所以我会添加另一个接受一些值的构造函数StudentID
。
您可以将其公开:
public int StudentId {get;set;}
或者,您可以使用单独的方法来更改它:
private int StudentId;
public void ChangeStudentId(int NewStudentId)
{
StudentId = NewStudentId;
}
干净的方法是将其设为公共属性,或者至少提供一个公共方法来更改 id。
public StudentID {get; set;}
// or
public StudentID {get; private set;}
public ChangeStudentID(int newID);
肮脏的方式是反射:
var instance = new Student();
var type = instance.GetType();
var propInfo = type.GetProperty("StudentID", BindingFlags.Instance | BindingFlags.NonPublic);
propInfo.SetValue(instance, 14, null);
您需要将其封装在公共方法中。最简单的方法(如果您使用的是 Visual Studio Pro 或更高版本)是右键单击声明它的属性,移动到“重构”并单击“封装字段”。VS 自动生成 get 和 set 修饰符。您可以删除eiter 以使该属性为只读或只写。
如果该属性声明为“int studentId”,则生成的封装将位于“Student.StudentId”(注意大写字母)。如果该属性被声明为“int StudentId”,那么据我所知,封装将默认为“Student.StudentId_1”。您可以在创建过程中选择自己的名称。
如果您使用的是 Visual Studio Express 或其他编辑器,只需执行以下操作:
public int StudentId() { return this.studentId; }
在这种情况下,您可以使用反射:
FieldInfo StudentIDField= typeof(Student).GetField("StudentId",BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
StudentIDField.SetValue(1);
您可以通过多种方式更改它......您可以将其Public
设为属性,或者您可以使用反射来更改它。
实际上,如果您的代码要更改 StudentID 并且现在它与另一个 Student 冲突怎么办?例如,如果您要创建一个控制学生的StudentCollection
类,则该类可能具有ChangeId
以下内容:
public class StudentCollection : List<Student>
{
public void ChangeId(Student student, int newId)
{
if(students.Where(s => s.Id == newId).Count() > 0)
throw new ArgumentException("A student already has that Id");
student.Id = newId;
}
}
那时您可以将 Id 设为内部,或使用方法来尝试减少有人直接修改它的机会。