I have been working on refactoring some code and then i make something like this. Main idea is that i have couple Methods which contains implementations and they change referenced string variable name in my case.
What i don't like here is situation that in every if statement returning same variable (but with different result).
So my question does someone have better idea for eventually refactoring this? Is there any problem doing this in if statements (from logical, clean code side etc).
All my methods have ref keyword (for string variable name). Sorry for confusion!
private string GenerateNameFrom(IRow row)
{
string name = string.Empty;
if (Method1(name,row))
return name;
else if (Method2(name,row))
return name;
else if (Method3(name,row))
return name;
else return "Null";
}
Here is one way to do it:
private string GenerateNameFrom(IRow row)
{
var name = "";
return (Method1(ref name) || Method2(ref name) || Method3(ref name)) ? name : "Null";
}
Using var to instantiate the empty string, no need to write string twice.
Using || means that the first method that returns true will satisfy the condition and no other method will be executed.
Using the ?: operator for conditional return.
Note: As Matthew Watson commented, you are probably missing the ref (or out keyword - because even though a string is a reference type, it's also immutable, so if you want your methods to effect the content of the name argument, you must either send it as ref or as out, since the only way to change it's value is to assign a new string to it.
(also converted the String.Empty to "", but that's just personal preference)
The variable name will always have an empty string. as you declare and initialize just before if statement
Any how below the short way to get the same result. The Result will be same of the below code and your code:
if (Method1(name) || Method2(name) || Method3(name))
{
return name;
}
else
{
return "Null";
}
Or more specifically using ternary operator
(Method1(name) || Method2(name) || Method3(name)) ? name : "Null";
Can't see the implementation of your methods but I'm assuming something like:
public bool Method1(ref string name)
{
if (condition)
{
name = "SomeValue";
return true;
}
return false;
}
You could refactor those methods to return the updated name:
public string Method1(name)
{
if(condition)
{
return "SomeValue";
}
return null;
}
And then you could just null coalesce the method calls:
private string GenerateNameFrom(IRow row)
{
string name = string.Empty;
return Method1(name)
?? Method2(name)
?? Method3(name)
?? "Null";
}
Well all of this Method1(name) and Method2(name) doing some validation over the input string name and returning bool. In that case would suggest you to combine all those validation logic inside single method using a switch statement probably and use that method instead
I would try to avoid using ref in this case. Instead, you could make the various methods return a tuple (bool success, string value) like so:
public static (bool success, string value) Method1(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
public static (bool success, string value) Method2(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
public static (bool success, string value) Method3(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
Then you can write the calling code like so (it's not shorter, but it avoids ref). Whether you like this better is probably a matter of taste...
private string GenerateNameFrom(/*IRow row*/)
{
string name = string.Empty;
var result = Method1(name);
if (result.success)
return result.value;
result = Method2(name);
if (result.success)
return result.value;
result = Method3(name);
if (result.success)
return result.value;
return null;
}
Alternatively, if null can be used to indicate "no result" then just do a similar thing but checking the return value for null:
private string GenerateNameFrom(/*IRow row*/)
{
string name = string.Empty;
var result = Method1(name);
if (result != null)
return result;
result = Method2(name);
if (result != null)
return result;
return Method3(name);
}
public static string Method1(string name)
{
if (name == "test")
return "changed";
return null;
}
public static string Method2(string name)
{
if (name == "test")
return "changed";
return null;
}
public static string Method3(string name)
{
if (name == "test")
return "changed";
return null;
}
Related
I have a VB.Net function that is useful for checking if a database record is null or not, and replace it with a default value if it is.
Public Function NZ(input As Object, Optional ifNull As Object = "") As Object
If IsDBNull(input) Or input Is Nothing Then
Return ifNull
Else
Return input
End If
End Function
I'm trying to get the same functionality in C#, but it doesn't like using objects the same way.
The closest I've gotten is
public static object NZ(object input, object ifNull)
{
if(input == DBNull.Value || input == null)
{
return ifNull;
}
else
{
return input;
}
}
but I get several errors with "cannot convert object to string" and the like.
I have tried to make a more specific version
public static string NZ(string input, string ifNull)
{
if (input == DBNull.Value || input == null)
{
return ifNull;
}
else
{
return input;
}
}
but that gives a "Operator '==' cannot be applied to operands of type string and DBNull"
I'm hoping there is an easy way to do this.
Use Convert.IsDbNull
The code will be something like this:
public static string NZ(object input, string ifNull)
{
return Convert.IsDbNull(input) ? ifNull : input;
}
If you want it to be more concise, write an extension method:
public static class DbNullExt
{
public static string ValueOrDefault(this object input, string ifNull)
=> Convert.IsDbNull(input) ? ifNull : input?.ToString();
public static string ValueOrDefaultIfDbNullOrNull(this object input, string ifNull)
=> Convert.IsDbNull(input) ? ifNull : input?.ToString() ?? ifNull;
}
And then simply invoke it as
var valueOrDefault = input.ValueOrDefault("ifItIsDbNull");
Use Information.IsDBNull
public object NZ(object input, object ifNull)
{
if (Information.IsDBNull(input) || input == null)
return ifNull;
else
return input;
}
I have this enum:
enum ControlsId
{
f1,
f2
}
And I want to return enum type from the function, like this:
public enum GetPostBackControlId(string str)
{
if(str = "btn1")
return ControlsId.f1
if(str = "btn2")
return ControlsId.f2
}
Is it possible to return enum from method?
public ControlsId GetPostBackControlId(string str)
{
if(str == "btn1")
{
return ControlsId.f1;
}
else if(str == "btn2")
{
return ControlsId.f2;
}
return (ControlsId)17;
}
I know an answer already exist, but something that may be a bit cleaner.
public TEnum GetEnum<TEnum>(string content)
{
return (TEnum)Enum.Parse(typeof(TEnum), content, true);
}
The beauty of this method, it is generic and highly reusable. As long as the value exist, it will parse into a valid enum. Otherwise, it will throw an exception. But if you intend to parse into an enum you tend to be aware of the type.
I have the following getter and setter method:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
if (partner == null)
{
// something like partner = " ";
}
return partner;
}
set
{
partner = value;
}
}
In the if clause i want to set partner = " ". But of course this isn't working, cause partner is a Typ a the class Ansprechpartner.
Is there a way to do something equivalent, so that partner returns an empty string if (partner == null)?
Please help
is Ansprechpartner your own class?
If it is, than you can return your own defenition of an "empty" Ansprechpartner
return Ansprechpartner.Empty;
and then define the empty property
public class Ansprechpartner
{
public static Ansprechpartner Empty
{
get
{
//generate an empty Ansprechpartner and return it here
}
}
You could override the ToString method from the Ansprechpartner and use a flag attribute like this:
public override ToString()
{
if (FlagAtrribute == null) //Or if it is a string, you could String.IsNullOrEmpty(FlagAtrribute)
{
return "";
}
return FlagAtrribute.ToString();
}
And in your getter just return a new empty instance of the Ansprechpartner class
get
{
if (partner == null)
{
partner = new Ansprechpartner();
}
return partner;
}
And in your code, do something like this:
MyClass.Partner.ToString();
If you change your return type from Ansprechpartner to object you can return anything you would like that derives from object. But I would strongly disagree with taking this approach. If you will want to rethink you're entire approach.
Your property doesn't actually appear to be working with strings, in which case returning a string would be an error.
However, answering your question directly of how to return a string, try something like this:
get
{
if (partner == null)
return String.Empty;
else
return partner;
}
}
Or, better yet:
get
{
return partner ?? String.Empty;
}
you could do something like:
get
{
if (partner == null)
return new Ansprechpartner() {whatever = ""};
else
return partner;
}
In my opinion there is a straightforward way to get exacly what you ask, that is to ensure that it is syntactically correct the folloging:
get
{
if (partner == null)
{
return = "";
}
return partner;
}
The way is to provide an implicict cast operator for the class. Thanks to implicit cast operator, the String.Empty or "" can be automatically casted to Ansprechpartner type, then it is perfectly legal the sysntax you use for the getter.
but what is a implicict cast operator ?
You can even see the question: How do I provide custom cast support for my class? for more detail.
I preferred, however, directly test the code for your class: the code used to successfully test it is the following:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
// legal assignment thanks to **public static implicit operator Ansprechpartner(string s)**
return partner ?? String.Empty;
}
set
{
partner = value;
}
}
We also try to make the inverse: thanks to public static implicit operator string(Ansprechpartner a) we see that is possible to assign an Empty string to a Ansprechpartner instance variabile
public void test_method()
{
Ansprechpartner s = String.Empty;
}
In the Ansprechpartner class we define cast operators
class Ansprechpartner
{
public static implicit operator Ansprechpartner(string s) {
// put your conversion logic here
// .. i.e: you can simply pass string s to a Ansprechpartner constructor
Ansprechpartner a = new Ansprechpartner();
return a;
}
public static implicit operator string(Ansprechpartner a)
{
if (a == null)
return "";
else
return a.ToString();
}
public Ansprechpartner()
{
}
public override string ToString()
{
return Value;
}
}
That's it, leave a comment if something has not been explained.
I cannot return null because my Hlist is a non nullable type. What else can I return in the place of null?
HList findHListentry(string letter)
{
if (string.IsNullOrWhiteSpace(letter))
{
HList result = listentry.Find(delegate(HList bk)
{
return bk.letter == letter;
});
return result;
}
else
{
return ?;
}
}
Use a Nullable<HList> instead?
HList? findHListentry(string letter)
{
///
return null;
}
There are several approaches of dealing with non-nullable value types:
Using Nullable<HList> (the shorthand name for it is HList?), or
Defining an "empty" HList entry, similar to how Microsoft defined one for Guid
Make your method return bool instead of HList, and return HList through an out parameter, the way it is done in Dictionary.TryGetValue
Using a special value:
struct HList {
public static HList Empty;
...
}
if (...) {
return HList.Empty;
}
Returning bool:
bool findHListentry(string letter, out HList res) {
...
}
If the input to the method truly shouldn't be null or an empty string, you could throw an exception:
HList findHListentry(string letter)
{
if (string.IsNullOrWhiteSpace(letter))
throw new ArgumentNullException("letter");
HList result = listentry.Find(
delegate(HList bk)
{
return bk.letter == letter;
}
);
return result;
}
(Note that I also reversed the conditional logic, since it sounded like you were looking for the opposite from the title of the question.)
You can also look into Code Contracts to verify preconditions for methods instead of manually checking the input and throwing an exception.
You have a few options:
If HList is a struct:
Make it into a class intead. Then you can return null.
Change the method signature to HList? findHListentry(string letter)
You might want to look into Nullable of T
If you didnt want to return a null, you could create a static instance of HList that's used to indicate it's an 'empty' value.
Similar to EventArgs.Empty
public static readonly HList EmptyHList = new Hlist() { /* initialise */ };
One implementation is to provide an Empty instance of the non-nullable type, and return that in place of null. Take string as an example...Whilst String is a nullable type in .NET, it contains a built in, readonly field called Empty, so with String you can do this:
if(mystring == null)
{
//My String Is Null
}
or, you could do this
if(mystring == String.Empty)
{
//My String is Empty
}
Whilst it is probably not the best approach, you could add an empty instance of HList to your class/struct. e.g.
HList findHListentry(string letter)
{
if (string.IsNullOrWhiteSpace(letter))
{
HList result = listentry.Find(delegate(HList bk) { return bk.letter == letter; });
return result;
}
else
{
return HList.Empty;
}
}
public struct HList
{
public const HList Empty;
}
Now you can do this in place of null
if(myHList == HList.Empty)
{
//My HList is Empty
}
I'm trying to run the following code but get a casting error.
How can I rewrite my code to achive the same ?
boolResult= (bool?)dataReader["BOOL_FLAG"] ?? true;
intResult= (int?)dataReader["INT_VALUE"] ?? 0;
Thanks
Use the "IsDbNull" method on the data reader... for example:
bool? result = dataReader.IsDbNull(dataReader["Bool_Flag"]) ? null : (bool)dataReader["Bool_Flag"]
Edit
You'd need to do something akin to:
bool? nullBoolean = null;
you'd have
bool? result = dataReader.IsDbNull(dataReader["Bool_Flag"]) ? nullBoolean : (bool)dataReader["Bool_Flag"]
Consider doing it in a function.
Here's something I used in the past (you can make this an extension method in .net 4):
public static T GetValueOrDefault<T>(SqlDataReader dataReader, System.Enum columnIndex)
{
int index = Convert.ToInt32(columnIndex);
return !dataReader.IsDBNull(index) ? (T)dataReader.GetValue(index) : default(T);
}
Edit
As an extension (not tested, but you get the idea), and using column names instead of index:
public static T GetValueOrDefault<T>(this SqlDataReader dataReader, string columnName)
{
return !dataReader.IsDBNull(dataReader[columnName]) ? (T)dataReader.GetValue(dataReader[columnName]) : default(T);
}
usage:
bool? flag = dataReader.GetValueOrDefault("BOOL_COLUMN");
There's an answer here that might be helpful:
https://stackoverflow.com/a/3308515/1255900
You can use the "as" keyword. Note the caution mentioned in the comments.
nullableBoolResult = dataReader["BOOL_FLAG"] as bool?;
Or, if you are not using nullables, as in your original post:
boolResult = (dataReader["BOOL_FLAG"] as bool?) ?? 0;
bool? boolResult = null;
int? intResult = null;
if (dataReader.IsDBNull(reader.GetOrdinal("BOOL_FLAG")) == false)
{
boolResult = dataReader.GetBoolean(reader.GetOrdinal("BOOL_FLAG"));
}
else
{
boolResult = true;
}
if (dataReader.IsDBNull(reader.GetOrdinal("INT_VALUE")) == false)
{
intResult= dataReader.GetInt32(reader.GetOrdinal("INT_VALUE"));
}
else
{
intResult = 0;
}
I'm sure I found the inspiration for this somewhere around the interweb but I can't seem to find the original source anymore. Anyway, below you find a utility class which allows to define an extension method on DataReader, like this:
public static class DataReaderExtensions
{
public static TResult Get<TResult>(this IDataReader reader, string name)
{
return reader.Get<TResult>(reader.GetOrdinal(name));
}
public static TResult Get<TResult>(this IDataReader reader, int c)
{
return ConvertTo<TResult>.From(reader[c]);
}
}
Usage:
reader.Get<bool?>("columnname")
or
reader.Get<int?>(5)
Here's the enabling utility class:
public static class ConvertTo<T>
{
// 'Factory method delegate', set in the static constructor
public static readonly Func<object, T> From;
static ConvertTo()
{
From = Create(typeof(T));
}
private static Func<object, T> Create(Type type)
{
if (!type.IsValueType) { return ConvertRefType; }
if (type.IsNullableType())
{
return (Func<object, T>)Delegate.CreateDelegate(typeof(Func<object, T>), typeof(ConvertTo<T>).GetMethod("ConvertNullableValueType", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new[] { type.GetGenericArguments()[0] }));
}
return ConvertValueType;
}
// ReSharper disable UnusedMember.Local
// (used via reflection!)
private static TElem? ConvertNullableValueType<TElem>(object value) where TElem : struct
{
if (DBNull.Value == value) { return null; }
return (TElem)value;
}
// ReSharper restore UnusedMember.Local
private static T ConvertRefType(object value)
{
if (DBNull.Value != value) { return (T)value; }
return default(T);
}
private static T ConvertValueType(object value)
{
if (DBNull.Value == value)
{
throw new NullReferenceException("Value is DbNull");
}
return (T)value;
}
}
EDIT: makes use of the IsNullableType() extension method defined like so:
public static bool IsNullableType(this Type type)
{
return
(type.IsGenericType && !type.IsGenericTypeDefinition) &&
(typeof (Nullable<>) == type.GetGenericTypeDefinition());
}
Here's my shot at an extension method. Column name semantics and falls back to default(T) when a null is encountered.
public static class DbExtensions
{
public static T ReadAs<T>(this IDataReader reader, string col)
{
object val = reader[col];
if (val is DBNull)
{
// Use the default if the column is null
return default(T);
}
return (T)val;
}
}
Here is the sample usage. Remember that despite string being a reference type, it will still fail to cast to null from a DBNull. The same is true with int?.
public Facility Bind(IDataReader reader)
{
var x = new Facility();
x.ID = reader.ReadAs<Guid>("ID");
x.Name = reader.ReadAs<string>("Name");
x.Capacity = reader.ReadAs<int?>("Capacity");
x.Description = reader.ReadAs<string>("Description");
x.Address = reader.ReadAs<string>("Address");
return x;
}
using extension method:
public static T GetValueOrDefault <T> (this SqlDataReader reader, string column) {
var isDbNull = reader[column] == DBNull.Value;
return !isDbNull ? (T) reader[column] : default (T);
}
Remember that a DBNull is not the same thing as null, so you cannot cast from one to the other. As the other poster said, you can check for DBNull using the IsDBNull() method.
Try this version. It performs some basic conversion and manages default values as well.