I have the following object where in my constructor I add a new Guid as the Id.
public class MyObject
{
public MyObject()
{
Id = Guid.NewGuid().ToString();
}
public String Id { get; set; }
public String Test { get; set; }
}
I want to do something like that in an object initializer :
var obj = new MyObject
{
Test = Id; // Get new GUID created in constructor
}
Is it possible?
No, you can't do that. You'd have to just set it in a separate statement:
var obj = new MyObject();
obj.Test = obj.Id;
The right-hand side of the property in an object initializer is just a normal expression, with no inherent connection to the object being initialized.
If this is something you regularly want to do with one specific type, you could add a method:
public MyObject CopyIdToTest()
{
this.Test = Id;
return this;
}
and then use:
MyObject obj = new MyObject().CopyIdToTest();
or with other properties:
MyObject obj = new MyObject
{
// Set other properties here
}.CopyIdToTest();
No -- you can't access an object's properties inside an initializer. The initializer is basically some syntactic sugar for programmers.
Consider situations like:
class Program
{
static void Main()
{
var Id = "hello";
var obj = new MyObject
{
Test = Id // Get new GUID created in constructor
};
}
}
The Id you'd assign (if your idea was valid, which again, it isn't) isn't necessarily the Id you'd be getting.
Related
public class Person
{
private string _myName;
public Person(string myName)
{
_myName= myName;
}
public string Name => _myName;
}
My understanding of object construction use is like this: var obj = new Person("Tim");
An init-only setter assigns a value to the property or the indexer element only during object construction. Following is sample code using init:
public class Person
{
private string _myName;
public string Name
{
get => _myName;
init => _myName= value;
}
}
What is the way to construct an object for such a class so that the init is invoked during object construction? For example, it is:
var obj = new Person("Tim");
var obj = new Person().Name("Tim");
var obj = new Person(); obj.Name="Tim";
I cannot find how object is created in init examples from this msdn link: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init
The problem is that your class Person doesn't expose a parameterless constructor, the only constructor your class has is one that takes a string as a parameter, meaning you cannot call new Person(); you must supply a parameter of type string. Meaning, the only way to create a new Person in you current example is:
var person = new Person("Anders Hejlsberg");
And after that you cannot modify Name as the initialisation of the object is complete. If you want to change the Name property later, you'll have to remove the init keyword and use a normal setter. If you want to initialize your object like
var person = new Person
{
Name = "Denis Ritchie"
};
(Side note: This is because new Person { ... } implicitly calls a parameterless constructor, i.e it's equal to new Person() { ... }, you could also do new Person("Richard Stallman") { ... } if you wanted to enforce that a Person must always have a Name)
You'll have to give your class a parameterless constructor (or remove your one and only constructor), I'd also recommend using an auto property (i.e no explicit backing field). Re-writing your class like so would result in this:
public class Person
{
public string Name { get; init; }
}
// usage
var person = new Person
{
Name = "Erich Gamma"
};
If you want to enforce that object of type Person always have a Name set, but still want to use init properties for other properties, you can do that like so:
public class Person
{
public string Name { get; init; }
public string Nickname { get; init; }
public Person(string name)
{
Name = name;
}
}
// usage
var linus1 = new Person("Linus Torvalds");
var linus2 = new Person("Linus Sebastian")
{
Nickname = "Linus 'TechTips' Sebastian"
};
It would simply be
var myPerson = new Person() { Name = "Tim" };
or, you can even omit the parenthesis, this would be valid.
var myPerson = new Person { Name = "Tim" };
Also, you can greatly simplify your example, you don't need to define the attribute myName. You can simply use the auto-properties like that:
public class Person
{
public string Name { get; init; }
}
Consider the following code snippet that does not compile.
class Class
{
public double Value { get; set; }
public int Frequency { get; set; }
}
class BoxAndWhisker
{
private readonly List<Class> _classes = new List<Class>();
public BoxAndWhisker()
{
Classes = _classes.AsReadOnly();
}
public IReadOnlyList<Class> Classes { get; }
}
class Program
{
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker
{
Classes =
{
new Class{ Value=1,Frequency=20},
new Class{Value=2,Frequency=10}
}
};
}
}
I want the property Classes to be read only right after baw is instatiated. How to do so? In other words, Classes must be writable in object initializer but read only in other places.
Edit
I prefer object initializer to parameterized constructor.
Why not pass Classes via constructor? E.g.
class BoxAndWhisker {
public BoxAndWhisker(params Class[] items) {
Classes = null != items
? new List<Class>(items).AsReadOnly()
: throw new ArgumentNullException(nameof(items));
}
public IReadOnlyList<Class> Classes { get; }
}
Then
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker(
new Class { Value = 1, Frequency = 20 },
new Class { Value = 2, Frequency = 10 }
);
...
}
Remove the
set;
From the properties within
Class
And make the Class have a Constructor which sets the initial values of the Properties, therefore they cannot be overwrote / changed
The "object initializer" syntax in C# has no semantic difference compared to a property value assignment.
You can read in the docs:
The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment.
So this:
var foo = new Bar { Baz = "baz" };
is completely equivalent to:
var temp = new Bar();
temp.Baz = "baz";
var foo = temp;
So you cannot restrict the property assignment the way you want.
The only solution is to use a constructor as proposed in the other answers.
You pass the IList<Class> instance to the BoxAndWhisker constructor and maintain a backing IReadOnlyList<Class> property
class BoxAndWhisker
{
public BoxAndWhisker(IList<Class> classes)
{
if (classes == null)
throw new ArgumentNullException(nameof(classes));
Classes = new ReadOnlyCollection<Class>(classes);
}
public IReadOnlyList<Class> Classes { get; }
}
The usage example
BoxAndWhisker baw = new BoxAndWhisker(new List<Class>
{
new Class {Value = 1, Frequency = 20},
new Class {Value = 2, Frequency = 10}
});
I want to deep copy of my complex C# object having DataTable as property.It is throwing error as "Table SalesData does not belong to this DataSet."
Here is my C# object:
public class Foo
{
public VehicleDetails VehicleDetails { get; set; }
public VehicleCondition VehicleCondition { get; set; }
public string Zipcode { get; set; }
public string StateCode { get; set; }
public DataTable SalesData { get; set; }
public DataTable OtherDataTable { get; set; }
}
I have used following code to clone object:
public static T CloneFullObject<T>(T i)
{
if (Object.ReferenceEquals(i, null)) return default(T);
var x = new XmlSerializer(i.GetType());
using (var m = new MemoryStream())
{
x.Serialize(m, i);
m.Seek(0, SeekOrigin.Begin);
return (T)x.Deserialize(m);
}
}
I am creating object as:
Foo foo = new Foo();
VehicleDetails vehicleDetail = new VehicleDetails();
// Fill vehicleDetail object
VehicleCondition vehicleCondition = new VehicleCondition ();
// Fill vehicleCondition object
foo.VehicleDetails = vehicleDetail;
foo.VehicleCondition = vehicleCondition;
DataTable salesData = getDataTable();
salesData.TableName = "salesData";
foo.SalesData = salesData;
DataTable otherData = getDataTable();
salesData.TableName = "otherData";
foo.OtherDataTable = salesData;
Below code is throwing error as:
System.InvalidOperationException: There was an error generating the XML document. ---> System.ArgumentException: Table salesData does not belong to this DataSet.
Foo clonefullObject = CloneFullObject(foo);
Please help if I am missing something before cloning object.
Note: both Datatable have value and it's not null.
Edit:
class Foo have some complex properties like:
private int _mileage;
public void SetMileage(int mileage) { _mileage = mileage; }
private int _expectedMileage;
public void SetExpectedMileage(int mileage) { _expectedMileage = mileage; }
public int GetMileage(bool flag)
{
return (flag)
? _mileage
: Math.Max(_mileage, _expectedMileage);
}
When cloning/copying objects you can simply clone/copy them. Serializing is quite expensive overkill, especially when implemented without concern for performance (you can read more in this SE question).
However, serialization is not your real problem, copying DataTable with both structure and data is. And it appears that your problem is not really your problem, your approach to it is your problem. DataTable.Copy() does all of that.
So how to do it? Well, how about properly?
On of proper approaches would be to implement ICloneable interface. It is kind of clumsy as return type is object. By implementing it on sub classes you can chain it deeper. I used as for casting in sample, have in mind that it will not generate exception on type mismatch. (As usually you can read more on some old SE question). You might, or might not, want to generate exceptions on faulty state (null) of DataTables.
public class Foo : ICloneable
{
//some fields....
private int _Bar; //private field
public void SetBar(int value) { _Bar = value; } //Field setter
public object Clone()
{
var result = new Foo()
{
_Bar = _Bar, // private members are accessible from their scope, even when object is different
Zipcode = Zipcode,
StateCode = StateCode,
SalesData = SalesData== null ? null : SalesData.Copy(),
OtherDataTable = OtherDataTable == null ? null : OtherDataTable.Copy(),
VehicleDetails = VehicleDetails.Clone() as VehicleDetails,
VehicleCondition = VehicleCondition.Clone() as VehicleCondition,
};
// alternatively you can call setter methods
result.SetBar(_Bar);
return result;
}
}
Notes:
You should work on creating object in better style, for example using Factory or at least use Object Initializer or constructor.
#SergeyBerezovskiy made a valid point by suggesting data model classes instead of full data tables.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
Is something like the following possible or do you have to return the list and assign it afterwards? I get object reference not set to instance of an object.
public class MyCollection
{
public List<SomeObject> Collection { get; set; }
public List<SomeObject> CreateCollection()
{
// Is there a way to set the Collection property from here???
this.Collection.Add(new SomeObject()
{
// properties
});
}
}
...
MyCollection collection = new MyCollection();
collection.CreateCollection();
Yes, you can use an object initializer:
public List<SomeObject> CreateCollection()
{
// You may want to initialize this.Collection somehere, ie: here
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject
{
// This allows you to initialize the properties
Collection = this.Collection
});
return this.Collection;
}
Note that this will still potentially have an issue - you are never initializing this.Collection in any code you're displaying. You will need to initialize it to a proper collection in your constructor or via some other mechanism.
It is also an odd choice to have a "Create" method that initializes the local variable and returns a List<T>. Typically, you'd do one or the other. A more common approach would be to place this code within the constructor:
public class MyCollection
{
public IList<SomeObject> Collection { get; private set; } // The setter would typically be private, and can be IList<T>!
public MyCollection()
{
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject
{
Collection = this.Collection
});
}
}
You could then use it via:
MyCollection collection = new MyCollection();
var object = collection.Collection.First(); // Get the first element
That being said, in general, there is no real reason to make a custom class for a collection like this in most cases. Just using a List<SomeObject> directly is typically sufficient.
It's completely possible - you just have to instantiate it first, before you can use it:
public List<SomeObject> CreateCollection()
{
this.Collection = new List<SomeObject>(); // this creates a new list - the default if you just define a list but don't create it is for it to remain null
this.Collection.Add(new SomeObject()
{
// whatever
});
}
Of course, as pointed out in a comment, if you want that function to return a list, it would have to actually return the list. Presumably you mean public void CreateCollection(), though, since that was your question, whether you actually had to return a list (answer: no).
You must initialize this.Collection before adding elements into it.
public List<SomeObject> CreateCollection()
{
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject()
{
// properties
});
}
You can use a list initializer in this case:
public class Person
{
public string Name { get; set; }
public string Firstname { get; set; }
}
class Program
{
public static List<Person> Collection { get; set; }
public static List<Person> CreateCollection()
{
return new List<Person>()
{
new Person() { Name = "Demo", Firstname = "Demo1"},
new Person() { Name = "Demo", Firstname = "Demo1"},
};
}
static void Main(string[] args)
{
Collection = CreateCollection();
}
}
I have a console aplication where I am trying to obtain the values of the properties of an object dynamically:
class Program
{
static void Main(string[] args)
{
DtoCartaCompromiso test = new DtoCartaCompromiso() { CodProducto = 1,
DescProducto = "aaa",
CodProveedor = 2,
DescProveedor = "bbb",
FechaExpiracion = DateTime.Now,
FechaMaxEntrega = DateTime.Now,
NumLote = "22" };
var testlist = new List<DtoCartaCompromiso>();
testlist.Add(test);
List<Header> columns = new List<Header>() { new Header{Name= "CodProducto"},new Header{Name= "NumLote"},new Header{Name= "DescProducto"},new Header{Name= "CodProveedor"},new Header{Name= "DescProveedor"},new Header{Name= "FechaExpiracion"},new Header{Name= "FechaExpiracion"},new Header{Name= "FechaMaxEntrega"} };
foreach (var d in testlist)
{
foreach (var col in columns)
{
string value = ((d.GetType().GetProperty(col.Name).GetValue(d, null)) ?? "").ToString();
Console.WriteLine(value);
}
}
Console.Read();
}
}
public class DtoCartaCompromiso
{
public int CodProducto;
public string NumLote;
public string DescProducto;
public int CodProveedor;
public string DescProveedor;
public Nullable<DateTime> FechaExpiracion;
public Nullable<DateTime> FechaMaxEntrega;
}
public class Header
{
public string Name;
}
i am getting the error "Object reference not set to an instance of an object" when I get to the line:
string value = ((d.GetType().GetProperty(col.Name).GetValue(d, null)) ?? "").ToString();
the error seems to occur when I get to the GetProperty() method, but I dont understand why
The problem is that you don't have properties there in your classes, they are public fields really. A public property looks like
public string PropertyName { get; set; }
but in your case there is lack of both getters and setters.
Change GetProperty() to GetField() and it will work. Or make your fields properties. Personally, I would go with the second option since it is a better idea to use properties instead of public fields.
Best guess without knowing more about your application, is the following sub-exression results in null:
d.GetType().GetProperty(col.Name)
At that point, the subsequent .GetValue() call will fail with your reported error.
Your property is probably not public. Make it public or pass System.Reflection.BindingFlags.NonPublic to your GetProperty call.
More info: http://msdn.microsoft.com/en-us/library/zy0d4103(v=vs.110).aspx