I'm pretty sure that I am duplicating a question, but somehow in my example it doesn't work, please see the code:
class Program
{
static void Main(string[] args)
{
Test test1 = new Test("str", "strrr");
}
}
class Test
{
public string testValue, mType;
public Test(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
}
public Test (string value) : this (value, messageType)
{
//want to manipulate value and messageType here
}
}
messageType in this constructor public Test (string value) : this (value, messageType) says it doesn't exist in the current context. I want to call it in this way because first of all I want my code instantiating the class with two strings, and then I want to provide value only to one parameter constructor but not lose messageType, because I will use it within this constructor public Test (string value). I read about chaining and instantiating constructors but it seems that this thing is opposite to what I read. Sorry not a lot practice yet with programming if this is a simple question, I would like to know how the code should look. What I have read before pointing this question: Call one constructor from another, How call constructor inside other constructor?, http://www.csharp411.com/constructor-chaining/, it doesn't work for me and again sorry if I am duplicating or doing silly things.
I think what you want to do is call Test test1 = new Test("Value", "MessageType"); to instantiate an object. Then the constructor with two strings will set these parameters to testValue and mType fields and call the first constructor to make manipulations.
In your code the first constructor does not call the second one, actually the second constructor calls the first one. If you want the first constructor to call the second your constructor signatures should be like this:
public Test(string value, string messageType) : this(value)
public Test(string value)
But here you cannot send messageType parameter to the second constructor. Therefore you should write an initialization method, put the content of the second constructor in this method and call it from both constructors and do not use constructor chaining.
public Test(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
Initialize();
}
public Test(string value)
{
this.testValue = value;
Initialize()
}
public void Initialize()
{
//This is the code in the second constructor
}
So in your example, you have to constructors: one accepting value and type and the other accepting only value. In such case, if the user provides a value only, the type should have a default assumed value. For example, you could do something like:
public Test (string value) : this (value, "Default Message Type")
{
}
What this code does is that it gets the value from the user, i.e. the caller of the constructor, and pass it to the other constructor, along with a default message called "Default Message Type".
Notice that you don't need to put any code in this constructor, since it will call the other constructor which will set both the value and the type.
Hope this helps.
EDIT: From the comments, I understood from that #ArnosGo wants to do some manipulation on value and add some logic that finds the value of messageType, then pass both to the other constructor. Unfortunately, it is not possible to do some manipulation on data before calling the other constructor, but here is a trick to do this:
class Test
{
public string testValue, mType;
public Test(string value, string messageType)
{
Initialise(value, messageType);
}
public Test (string value)
{
// Do some manipulation here and found out the value of messageType.
Initialise(value, messageType);
}
protected void Initialise(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
}
}
Basically, you are creating a function that does what both constructors do, then the constructors only calculate the values and pass them to that function.
The call to the database and message string comes before creating an
object of Test class and then i want to put two values in it, and then
manipulate those values inside and provide them to constructor with
one parameter. If that explains something.
Based on OP's comment, I think approach with static method will be better
Because values are manipulated only once and properties assigned only once.
public class Test
{
private static ManipulateValues(string value, string msgtype)
{
//Do your manipulating
Return manipulatedValue;
}
public static Create(string value, string msgtype)
{
return new Test(Test.ManipulateValues(value, msgtype), msgtype);
}
public Test(string value, string msgType)
{
this.testValue = value;
this.mType = messageType;
}
}
Then use it:
string messageType = someValue;
string value = someDatabaseValue;
Test temp = Test.Create(value, messageType)
Related
I have a basic filter class that stores a string parameter name and a generic T value. The filter has a method Write(writer As IWriter) which will write the contents of the filter to an HTML page. The Write method has two overloads, one which takes two strings and which takes a string and an object. This lets me auto-quote strings.
The problem is, when I call writer.Write(ParameterName, Value) and T is a string, it calls the overload for string/object, not string/string! If I call the Write method on the writer directly, it works as expected.
Here's an SSCE in C#. I tested this in both VB and C# and found the same problem
void Main() {
FooWriter writer = new FooWriter();
Filter<string> f = new Filter<string>() {ParameterName = "param", Value = "value"};
f.Write(writer); //Outputs wrote w/ object
writer.Write(f.ParameterName, f.Value); //Outputs wrote w/ string
}
class FooWriter {
public void Write(string name, object value) {
Console.WriteLine("wrote w/ object");
}
public void Write(string name, string value) {
Console.WriteLine("wrote w/ string");
}
}
class Filter<T> {
public string ParameterName {get; set;}
public T Value {get; set;}
public void Write(FooWriter writer) {
writer.Write(ParameterName, Value);
}
}
The problem is, when I call writer.Write(ParameterName, Value) and T is a string, it calls the overload for string/object, not string/string!
Yes, this is expected - or rather, it's behaving as specified. The compiler chooses the overload based on the compile-time types of the arguments, usually. There's no implicit conversion from T to string, so the only applicable candidate for the invocation of writer.Write(ParameterName, Value) is the Write(string, object) overload.
If you want it to perform overload resolution at execution time, you need to use dynamic typing. For example:
public void Write(FooWriter writer) {
// Force overload resolution at execution-time, with the execution-time type of
// Value.
dynamic d = Value;
writer.Write(ParameterName, d);
}
Note that this could still behave unexpectedly - if Value is null, then it would be equivalent to calling writer.Write(ParameterName, null) which would use the "better" function member - here writer.Write(string, string) - even if the type of T is object!
I would like to create a function allow to get data from any classes with provide a key value, but I am stack when converting object back to the class. The following is my code.
var ListABC = new List<ABC>();
GetData(ListABC, typeof(ABC), "A1");
Here is my Function :-
Public void GetData(object obj, Type objType, string find)
{
// Note! not able to using (List<ABC>)obj, because you never know what tyoe of object will be pass in.
// How to get list data of "A1" after List ABC as a object? assume this function allow any classes.
}
Here is my class :-
public class ABC {
protected int _A1;
protected bool _B1;
protected string _C1;
public int A1
{
get
{
return this._A1;
}
set
{
this._A1 = value;
}
}
public bool B1
{
get
{
return this._B1;
}
set
{
this._B1 = value;
}
}
public string C1
{
get
{
return this._C1;
}
set
{
this._C1 = value;
}
}
}
As Daniel said, make GetData generic:
public void GetData<T>(IList<T> obj, string find)
{
}
and then call it like so:
GetData(ListABC, "A1");
You can even enforce constraints on T, for example:
public void GetData<T>(IList<T> obj, string find)
where T: IConvertible
{
}
If you don't want to implement an interface on the list item objects you will pass here, you could also pass a func:
public void GetData<T>(IList<T> obj, Func<T, string> idFunc, string find)
{
var matchingItems = obj.Where(o => idFunc(o) == find);
}
and call it like so:
GetData(ListABC, i => i.A1, "A1");
Edit: Do you just want ListABC.Select(i => i.A1) ?
If you want minimum change in your code. you can do it like below.
Although, making method generic is good idea, but as you are already passing type of ABC to the method, you are not required to make method generic.
here type you have passed is suggesting which type of data list is holding
Assumptions: you method's return type is void (so assuming you don't want anything to be returned. and also you are passing only one string find as a property to get so at a time you want data of only specified property.
if your requirements are simpler and scope of data is limited in your method only, you can always choose simpler way (which is easily understandable and readable)
try something like below,
public void GetData(object obj, Type objType, string find)
{
//as you are passing type of list here, you can use it.
if(objType == typeof(ABC))
{
List<ABC> list = (List<ABC>)obj;
//now use it.
//here we are getting the property with name as per find (name we passed in method)
PropertyInfo prop = objType.GetProperty(find);
//if there is no property with specified name, PropertyInfo object (prop) will be null
if (prop != null)
{
if (prop.PropertyType == typeof(int))
{
foreach (ABC abcObj in list)
{
object a1Data = prop.GetValue(abcObj);
int data = (int)a1Data;
}
}
}
}
}
Note: drawback of this approach is, you need to handle cases of different Types in this method. So if your method may accept big variety of type, you may not want to go with this idea.
I have a basic filter class that stores a string parameter name and a generic T value. The filter has a method Write(writer As IWriter) which will write the contents of the filter to an HTML page. The Write method has two overloads, one which takes two strings and which takes a string and an object. This lets me auto-quote strings.
The problem is, when I call writer.Write(ParameterName, Value) and T is a string, it calls the overload for string/object, not string/string! If I call the Write method on the writer directly, it works as expected.
Here's an SSCE in C#. I tested this in both VB and C# and found the same problem
void Main() {
FooWriter writer = new FooWriter();
Filter<string> f = new Filter<string>() {ParameterName = "param", Value = "value"};
f.Write(writer); //Outputs wrote w/ object
writer.Write(f.ParameterName, f.Value); //Outputs wrote w/ string
}
class FooWriter {
public void Write(string name, object value) {
Console.WriteLine("wrote w/ object");
}
public void Write(string name, string value) {
Console.WriteLine("wrote w/ string");
}
}
class Filter<T> {
public string ParameterName {get; set;}
public T Value {get; set;}
public void Write(FooWriter writer) {
writer.Write(ParameterName, Value);
}
}
The problem is, when I call writer.Write(ParameterName, Value) and T is a string, it calls the overload for string/object, not string/string!
Yes, this is expected - or rather, it's behaving as specified. The compiler chooses the overload based on the compile-time types of the arguments, usually. There's no implicit conversion from T to string, so the only applicable candidate for the invocation of writer.Write(ParameterName, Value) is the Write(string, object) overload.
If you want it to perform overload resolution at execution time, you need to use dynamic typing. For example:
public void Write(FooWriter writer) {
// Force overload resolution at execution-time, with the execution-time type of
// Value.
dynamic d = Value;
writer.Write(ParameterName, d);
}
Note that this could still behave unexpectedly - if Value is null, then it would be equivalent to calling writer.Write(ParameterName, null) which would use the "better" function member - here writer.Write(string, string) - even if the type of T is object!
Let's say, for example, we have a method, which for sake of argument we'll call MethodOne;
public void MethodOne()
{
//do stuff.
}
Now let's say we want to create an optional peramater, and we might decide to create another method with the same name, that takes different overloads, for example;
public void MethodOne()
{
//do stuff.
}
public void MethodOne(bool checkVar)
{
if(checkVar)
{
//do stuff
}
else
{
//do other stuff
}
}
So now we've got a method which has two different overload combinations(?). Is this, in practise, better than having one method, and just checking whether the optional overload is null or contains information, for example;
public void MethodOne(int? testVar)
{
if(testVar != null)
{
//do stuff
}
}
This may seem trivial with just one overload, but imagine that i've got 5 variables i want to pass through, would i create 5 methods, same name with different overloads, or just one method and check the passed variables?
There are a few workarounds for this. You could, for example, use an enumerator and an Object array as second parameter which contains real parameter values so that you know what to do with data by switching the enumerator... or you could just declare 5 Object parameters and then check for their type in a switch, box them accordingly and proceed. But both options are very bad practices.
I suggest you to stick on different overloads:
public void MethodOne(Boolean value)
{
// Process the value...
}
public void MethodOne(Int32 value)
{
// Process the value...
}
public void MethodOne(Int32 value, String text)
{
// Process the value and the text...
}
// And so on...
Or default data in parameter declarations:
public void MethodOne(Int32 integer = 1, String text = "hello", ...)
{
// Process everything inside the method...
}
Or parametrized methods (if every object type has a common processing):
public void MethodOne(params Object[] parameters)
{
for (int i = 0; i < parameters.Length; ++i)
// Check type of parameter and process the value...
}
Or methods bubbling if your design allows it (which is my favorite one as the first one is just producing a lot of code redundancies and the second one may be sometimes confusing for you or other developers working with you):
public void MethodOne(Int32 value)
{
MethodOne(value, "hello");
}
public void MethodOne(Int32 value, String text)
{
// Process everything inside the method...
}
What you can do is use optional arguments:
public void MethodOne(int testVar = 0)
{
if(testVar != 0)
{
//do stuff
}
}
You generally bubble down on overloads like this:
public void MethodOne()
{
MethodOne(1)
}
public void MethodOne(int testVar)
{
MethodOne(testVar, "test")
}
public void MethodOne(int testVar, string testString)
{
MethodOne(testVar, testString, null)
}
public void MethodOne(int testVar, string testString, object testObject)
{
// Do your actual code here
}
This would be equivalent to
public void MethodOne(int testVar = 1, string testString = "test", object testObject = null)
{
// Do your actual code here
}
But usually you should prever overloads over default parameters. Also, by 'bubbling down' like in my example you avoid having redundant code or redundant 'default parameters'
As the number of arguments increase, I wouldn't want to look through a method's nested if/else logic to determine what arguments are being used or not. It's hard to read, understand, maintain and can lead to bugs. Use overloads and keep your methods concise, lean and maintainable.
public static void SendEmail(String from, String To, String Subject, String HTML, String AttachmentPath = null, String AttachmentName = null, MediaTypeNames AttachmentType = null)
{
....
// Add an attachment if required
if (AttachmentPath != null)
{
var ct = new ContentType(MediaTypeNames.Text.Plain);
using (var a = new Attachment(AttachmentPath, ct)
{
Name = AttachmentName,
NameEncoding = Encoding.UTF8,
TransferEncoding = TransferEncoding.Base64
})
{
mailMessage.Attachments.Add(a);
}
}
....
}
As you can see the MediaTypeNames AttachmentType throws the error:
'System.Net.Mime.MediaTypeNames': static types cannot be used as parameters
What is the best way to deal with this?
You can't pass a static type to a method as a parameter because then it would have to be instantiated, and you can't create an instance of a static class.
It's not recommended but you can simulate use of Static classes as parameters.
Create an Instance class like this :
public class Instance
{
public Type StaticObject { get; private set; }
public Instance(Type staticType)
{
StaticObject = staticType;
}
public object Call(string name, params object[] parameters)
{
MethodInfo method = StaticObject.GetMethod(name);
return method.Invoke(StaticObject, parameters);
}
public object Call(string name)
{
return Call(name, null);
}
}
Then your function where you would use the static class :
private static void YourFunction(Instance instance)
{
instance.Call("TheNameOfMethodToCall", null);
}
For instance.Call :
The first parameter is the name of the method of your static class to call
The second parameter is the list of arguments to pass to the method.
And use like this :
static void Main(string[] args)
{
YourFunction(new Instance(typeof(YourStaticClass)));
Console.ReadKey();
}
The best deal is definitely to remove the last parameter. Since type is static you don't need a reference to an instance and you can refer to its members from your function body.
Use a different type for the argument.
A method argument needs to be of a type that can accept a reference to an instance, so it can't be a static class.
You can wrap static types around an interface or another non-static class and add that as the parameter. Not ideal but a way around it. Or simply just reference the static type in the method body itself.
Send a static class as the type of the parameter
and then give it a variable name for use in the function.
This works because the new variable is a reference to the static class.
It is necessary to address the global variable problem.
If you use a static class as a variable inside a method,
you need to pass it in as a parameter, to avoid the global variable issue.
This is basic structured programming 101 from the 80's.
It doesn't look like you even use that parameter in your method. You should just remove it because MediaTypeNames cannot be instantiated anyway.
A workaround to passing static parameters is to pass it as an object.
Function:
public static void HoldKey(object key)
{
...
}
Call function:
Function(static param);