I'm sure there was a way to easily create an instance of a class but my search of the great interwebs hasn't found it. Lets say I have this:
List<LicencedCustomer> leftList = new List<LicencedCustomer>();
leftList.Add(new LicencedCustomer (LMAA_CODE:"1",LICENSE_NUMBER:"1",TRADING_NAME:"Bobs Liquor",STATE:"NSW",POSTCODE:"2261"));
My class looks like the below.
public class LicencedCustomer
{
public string LMAA_CODE {get; set;}
public string LICENSE_NUMBER {get; set;}
public string TRADING_NAME {get; set;}
public string STATE {get; set;}
public string POSTCODE {get; set;}
public LicencedCustomer(string LMAA_CODE, string LICENSE_NUMBER, string TRADING_NAME, string STATE, string POSTCODE)
{
this.LMAA_CODE = LMAA_CODE;
this.LICENSE_NUMBER = LICENSE_NUMBER;
this.TRADING_NAME = TRADING_NAME;
this.STATE = STATE;
this.POSTCODE = POSTCODE;
}
...
Without the constructor immediately above, I get an error that the class doesn't contain a constructor that takes 5 arguments (initially I tried it with the values only and no field names in the List.Add function).
Is there a shortcut that allows assignment to properties on creation, without needing to define the constructor explicitly?
Thanks!
EDIT: Wide ranging curiosity has resulted from the capitalised properties - they are only that way because they've been built to reflect the headings of an import file. Not my preferred method!
When you use new ( ) you call a constructor that matches the parameters. If you have no defined constructors you will get an implicit parameter less constructor.
To use the shortcut initializer use something like this.
public class sCls
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"};
}
Edit
From comments if you add a consturctor that takes a paramter you lose the implict paramterless constructor
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"}; // ERROR error CS1729: 'csCA.Program.sCls' does not contain a constructor that takes 0 arguments
}
You can also use any constructor with the initializer list
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls("hi") {A = 4, B = "HI"};
}
Remember that in all cases the constructor is called before the initializer list even if it has a parameter less constructor. So base class constructions or anything else that happens in the construction of the object will happen first.
public class BSE
{
public BSE()
{
BaseA = "Bob";
}
public string BaseA;
}
public class sCls :BSE
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI" };
Console.WriteLine("{0}", oCls.BaseA);//Prints Bob
}
Add a default constructor, then try something like:
new LicencedCustomer() { LMAA_CODE = ..., LICENSE_NUMBER = ..., ... };
Side note: It's not conventional to capitalize properties.
Related
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 have this assignment:
Counts.btnCountViewsAvg.BtnCount = 123;
Here are the classes that I use:
public static class Counts
{
public static BtnCountViews btnCountViewsAvg;
}
public class BtnCountViews // this class used in many places
{
public int BtnCount { get; set; }
public int Views { get; set; }
}
What I would like to do is to assign 123 to BtnCount but it says cannot assign to a null. When I check the btnCountViewsAvg is null. I used static as I only want to have one Counts class in the application.
Can someone give me some advice on how I can assign a value to Counts.btnCountViewsAvg.BtnCount
It is your Counts.btnCountViewsAvg that is null. You need to instantiate that before being able to set the BtnCount property.
To instantiate the value you need to do the following:
Counts.btnCountViewsAvg = new BtwCountViews();
Furthermore you could instantiate using the object initialiser it like so:
Counts.btnCountViewsAvg = new BtwCountViews { BtnCount = 123 };
In order to ensure that btnCountViewsAvg is only created once you could do the following:
public static class Counts
{
public readonly static BtnCountViews btnCountViewsAvg = new BtnCountViews();
}
Or to follow on from Jon Skeets suggestion with using a property rather than a public field this would be a better approach:
public static class Counts
{
public static ButtonCountViews ButtonCountViewsAvg { get; } = new ButtonCountViews();
}
Note I renamed your class to remove the abbreviation.
You have two options:
Create new object only once
public static class Counts
{
public static BtnCountViews btnCountViewsAvg = new BtnCountViews();
}
Or create it every time you need it:
Counts.btnCountViewsAvg = new BtnCountViews()
{
BtnCount = 123
};
You, probably, want something like this: create an instance of BtnCountViews with BtnCount = 123 and assign it to static field:
public static class Counts
{
// we create a instance: new btnCountViewsAvg()
// then we set up a property of this instance: { BtnCount = 123, }
public static BtnCountViews btnCountViewsAvg = new btnCountViewsAvg() {
BtnCount = 123,
};
}
I am trying to create some sort of mapping and construct a switch statement based on this.
The first thing I tried was this:
public class Class1
{
public void Test()
{
string testString_A = "A";
string testString_B = null;
switch (testString)
{
case Options.O1.aName:
testString_B = Options.O1.bName;
break;
case Options.O2.aName:
testString_B = Options.O2.bName;
break;
}
}
}
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
public class Option
{
public string aName;
public string bName;
}
In this scenario, compiler complains that a constant value is expected for the switch cases.
So next, I tried the following but it does not work either. The .aName I try to use in the switch statement seems not accessible.
public Class1()
{
public void Test()
{
string testString = "A1";
switch (testString)
{
case Options.O1.aName:
...
}
}
}
public static class Options
{
public static Option_O1 O1 = new Option_O1();
public static Option_O2 O2 = new Option_O2();
}
public class Option_O1
{
public const string aName = "A1";
public const string bName = "B1";
}
public class Option_O2
{
public const string aName = "A2";
public const string bName = "B2";
}
How can I accomplish what I want?
There's a big difference between a string property / field variable (even if it is static or readonly), and a const string. The switch statement requires either literals, or const values in the case statements.
This explains why your first attempt didn't succeed (Error : "A Constant value is required").
In the second case, although you could obviously do this:
switch (testString)
{
case Option_O1.aName:
return Option_O1.bName;
case Option_O2.aName:
return Option_O2.bName;
}
but as soon as you try and 'cheat' the constant switch requirement by introducing the static class container, you're back to the same problem, although a more cryptic compiler error:
case Options.O1.aName: // Cannot be accessed by an instance reference
return Option_O1.bName;
Alternative to switch
I'm guessing here, but it seems that you need to build a run time mapping function.
Assuming that you always want to return the same data type (a string), I would suggest using a Dictionary keyed by the string you are trying to 'switch' on - this mapping can be built up at run time.
Here's an example of a statically bootstrapped map:
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
private static IDictionary<string, Option> myOptionMap = new []
{
Options.O1, Options.O2
}
.ToDictionary(x => x.aName);
Which you can use like so:
public string Test(string someAName)
{
if (myOptionMap.TryGetValue(someAName, out var myOption))
{
return myOption.bName;
}
// Oops not found
return string.Empty;
}
Unless there's more to this than your MVP, it's unlikely that you'll want to subclass your options per instance - Option_O1
The classes below consist of
A - father class
B - Child class
Holder - Contains a list of A's
I want to reach a child property from the list of fatherobjects. Why cant I do this? Or better question, how do I do this?
public class A
{
public int var = 0;
}
public class B : A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public B()
{
}
public B(B p_B)
{
Property1 = p_B.Property1;
Property2 = p_B.Property2;
}
}
class Holder
{
private List<A> m_Objects = new List<A>();
public void AddObject(A p_Object)
{
m_Objects.Add(p_Object);
}
public void AddObjectProperty1(B p_B)
{
// At this point, m_Objects holds a B-object. And I want to add the value from Property1
// but there is no Property1 in the A-class so I cant do this. How do I use the base.values from
// a statement like the one below?
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
if (index > -1)
m_Objects.ElementAt(index).Property1 += p_B.Property1;
}
}
class Program
{
static void Main(string[] args)
{
// Class to hold the objects
Holder h = new Holder();
// Create a B object
B b = new B();
b.Property1 = 1;
b.Property2 = 2;
// Place a new instance of the B-object in a list of A's
h.AddObject(new B(b));
// Add the value from Property1 to the value in the b-object in the a-list. :P
h.AddObjectProperty1(b);
Console.WriteLine(++b.var);
Console.ReadLine();
}
}
You can use type casting:
(m_Objects[i] as B).Property1
Or
((B)m_Objects[i]).Property1
At compile-time there is no possibility for the compiler to know, you would only add Bs to your list of As. So there is no guarantee whatsoever that each item in the following query is an instance of B and thus has Property1
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
First possibilty is casting as in Artyom's answer. But this will fail if you not all of the elements in the List are really Bs. So if you rely on all Elements in m_Objects to be instances of B, why don't you just use List<B> m_Objects?
If you need the mixed list, you have to do a type-check in the query to ensure, you are dealing with an instance of Bbefore casting.
int index = m_Objects.FindIndex(item => (item is B) && (item as B).Property1 == p_B.Property1);
See this DotNetFiddle Example
I saw an example on MSDN where it would let you specify the default value if nothing is returned. See below:
List<int> months = new List<int> { };
int firstMonth2 = months.DefaultIfEmpty(1).First();
Is it possible to use this functionality with an object? Example:
class object
{
int id;
string name;
}
code:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(/*something to define object in here*/).name;
UPDATE:
I was thinking I could do something like this:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(new myObjec(-1,"test")).name;
But haven't been able to. It should be noted that I am actually trying to use this method on an object defined in my DBML using LINQ-To-SQL. Not sure if that makes a difference in this case or not.
You need to pass an instantiated class as a parameter of the DefaultIfEmpty.
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test() { i = 1, name = "testing" }).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
}
To add to it and make it a bit more elegant (IMO) add a default constructor:
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test()).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
public Test() { i = 2; name = "testing2"; }
}
As per the MSDN page on this Extension Method you can do what you want:
http://msdn.microsoft.com/en-us/library/bb355419.aspx
Check the sample on this page for an example on how to use this with an object.
i must admit i am not too sure i understand your question, but i'll try to suggest using double question mark if the returned object might be null. Like so:
myList.FirstOrDefault() ?? new myObject();
You can create a default Object Like this:
Object o_Obj_Default = new Object();
o_Obj_Default.id = 3;
o_Obj_Default.name = "C";
And add it to your default value :
string defaultName = objs.DefaultIfEmpty(o_Obj_Default).First().name;
If your list "objs" is empty, the result will be "C"