I don't know if I'm missing something here but isn't it strange that my code below always raises an exception on List.Contains part although I know for sure that list contain that element:
using System;
using System.Linq;
using System.Collections.Generic;
class SomeClass
{
public string param1 {get; private set;}
public string param2 {get; private set;}
private SomeClass(){}
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if(!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main (string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Quote from the documentation of the Contains method:
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable(Of T).Equals method for T (the type of values in the list).
So you could implement IEquatable<T> on your objects if you want the Contains method to determine if 2 instances of SomeClass are equal:
class SomeClass: IEquatable<SomeClass>
{
public string param1 { get; private set; }
public string param2 { get; private set; }
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public bool Equals(SomeClass other)
{
return param1 == other.param1 && param2 == other.param2;
}
}
Another possibility is to implement a custom EqualityComparer<T>:
class SomeClassEqualityComparer : IEqualityComparer<SomeClass>
{
private static readonly SomeClassEqualityComparer _instance = new SomeClassEqualityComparer();
public bool Equals(SomeClass x, SomeClass y)
{
return x.param1 == y.param1 && x.param2 == y.param2;
}
public int GetHashCode(SomeClass obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + obj.param1.GetHashCode();
hash = hash * 23 + obj.param2.GetHashCode();
return hash;
}
}
public static IEqualityComparer<SomeClass> Instance
{
get { return _instance; }
}
}
and then use the following overload of the Contains method:
if (!myList.Contains(someClass, SomeClassEqualityComparer.Instance))
throw new System.ArgumentException("some error");
You're not removing the same instance of SomeClass. This will work:
public static void Main ()
{
var _someClass = new SomeClass2();
var someClass = new SomeClass("aaa", "bbb");
_someClass.Add(someClass);
try
{
_someClass.Remove(someClass);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
To make your original code work you would need to implement IEquatable. See http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx.
Sorry I didn't spend more time on the hash code implementation. I don't even remember if ^ is the right xor operator... I suppose I could rot13 before the xor, but that seemed kinda silly.
using System;
using System.Collections.Generic;
namespace DoesItCompile
{
class SomeClass
{
private object param1;
private object param2;
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public override bool Equals(object oThat)
{
if (!(oThat is SomeClass))
return false;
SomeClass scThat = (SomeClass)oThat;
if (!string.Equals(this.param1, scThat.param1))
return false;
if (!string.Equals(this.param2, scThat.param2))
return false;
return true;
}
public override int GetHashCode()
{
return this.param1.GetHashCode() ^ this.param2.GetHashCode();
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if (!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main(string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
Console.WriteLine("Have a nice president's day.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
}
}
P.S. - I've no clue why you brought Zelda's stalker into the question, but I'm sure there's a good reason.
Related
I have 3 different classes but the same methods inside them. Need to check before usage and apply the right instance of them c#. The calling methods are the same but different logic inside. I need to be able to call the right instance at the right time. I tried everything and it appears that I am failing.
Interface is not an option because these assemblies come in the form of DLLs. I dont have the source code for them.
public VersionAssembly240 obj1 = new VersionAssembly240();
public VersionAssembly250 obj2 = new VersionAssembly250();
public VersionAssembly260 obj3 = new VersionAssembly260();
void Main()
{
ChooseRightInstance(null, obj2, null, "v25");
}
public void ChooseRightInstance(VersionAssembly240 obj1, VersionAssembly250 obj2, VersionAssembly260 obj3, string version)
{
if (version == "v24")
{
var obj = obj1;
}
else if (version == "v25")
{
var obj = obj2;
}
else
{
var obj = obj3;
}
//I need to be able to access the obj var somce the 3 classess have the same access methods
obj
}
//for testing
public class VersionAssembly260
{
public string example()
{
return "v26";
}
}
public class VersionAssembly250
{
public string example()
{
return "v25";
}
}
public class VersionAssembly240
{
public string example()
{
return "v24";
}
}
You have to crate an interface with method example() and different implementations for each class.
public interface IVersionAssembly
{
string example();
}
Implement method example()
public class VersionAssembly260 : IVersionAssembly
{
public string example()
{
return "v26";
}
}
public class VersionAssembly250 : IVersionAssembly
{
public string example()
{
return "v25";
}
}
public class VersionAssembly240 : IVersionAssembly
{
public string example()
{
return "v24";
}
}
Now use interface IVersionAssembly in method ChooseRightInstance
public void ChooseRightInstance(VersionAssembly240 obj1, VersionAssembly250 obj2, VersionAssembly260 obj3, string version)
{
IVersionAssembly obj;
if (version == "v24")
{
obj = obj1;
}
else if (version == "v25")
{
obj = obj2;
}
else
{
obj = obj3;
}
obj.example();
}
You could potentially achieve this using an Interface, assuming that the real-world versions of these classes all have the same public methods.
Live demo: https://dotnetfiddle.net/63hjQt
Code. See the comments inline for more info on each important part:
using System;
public class Program
{
public static void Main() {
VersionAssembly240 obj1 = new VersionAssembly240();
VersionAssembly250 obj2 = new VersionAssembly250();
VersionAssembly260 obj3 = new VersionAssembly260();
ChooseRightInstance( null, obj2, null , "v25" );
}
public static void ChooseRightInstance(VersionAssembly240 obj1, VersionAssembly250 obj2, VersionAssembly260 obj3, string version)
{
IVersionAssembly obj; //declare the object outside the if, as an instance of the interface
if (version == "v24")
{
obj = obj1;
}
else if (version == "v25")
{
obj = obj2;
}
else
{
obj = obj3;
}
Console.WriteLine(obj.example()); //can call the example() method because the interface defines it
}
}
//interface which defines the methods which all the classes must implement
public interface IVersionAssembly
{
string example();
}
//all the classes implement the interface, but within the methods they can use different concrete implementations
public class VersionAssembly260 : IVersionAssembly
{
public string example()
{
return "v26";
}
}
public class VersionAssembly250 : IVersionAssembly
{
public string example()
{
return "v25";
}
}
public class VersionAssembly240 : IVersionAssembly
{
public string example()
{
return "v24";
}
}
Here's the Microsoft guide to interfaces in C#: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/
You can try below
// make abstract base class
public abstract class BaseVersionAssembly
{
public abstract string example();
}
public class VersionAssembly260 : BaseVersionAssembly
{
public override string example()
{
return "v26";
}
}
public class VersionAssembly250 : BaseVersionAssembly
{
public override string example()
{
return "v25";
}
}
public class VersionAssembly240 : BaseVersionAssembly
{
public override string example()
{
return "v24";
}
}
ChooseRightInstance function
public string ChooseRightExample(BaseVersionAssembly obj)
{
return obj.example();
}
I've created a class "BankAccount.cs" and am using xunit to test it. I'm testing whether the constructor throws an ArgumentException if it's provided with an empty string as an argument (the argument is the bank account number as a string).
My test fails because no Exception is being thrown - I can't figure out why not.
It appears that the constructor isn't even being called; if I let the constructor throw an Exception (rather than implementing this in the setter of AccountNumber), none is thrown either. Also, if I use Console.WriteLine to debug manually, nothing is written to the console.
Exceptions (Debugging) are set to default settings.
using System;
using System.Collections.Generic;
namespace Banking.Models
{
public class BankAccount : IBankAccount
{
/* NOTE: I've deleted non-relevant fields, properties and methods for brevity */
private string _accountNumber;
public string AccountNumber
{
get { return _accountNumber; }
set
{
if(value == string.Empty)
throw new ArgumentException("Accountnumber must have a value");
_accountNumber = value;
}
}
public BankAccount(string account)
{
AccountNumber = account;
Balance = Decimal.Zero;
_transactions = new List<Transaction>();
}
public override string ToString()
{
return $"{AccountNumber} - {Balance}";
}
public override bool Equals(object obj)
{
BankAccount account = obj as BankAccount;
if (account == null) return false;
return AccountNumber == account.AccountNumber;
}
public override int GetHashCode()
{
return AccountNumber?.GetHashCode() ?? 0;
}
}
}
Tests:
using System;
using Xunit;
using Banking.Models;
namespace Tests.Models
{
public class BankAccountTest : IDisposable
{
// private variables
private BankAccount _account;
private string AccountNumber { get; set; }
// Setup
public BankAccountTest()
{
AccountNumber = "123-4567890-02";
_account = new BankAccount(AccountNumber);
}
[Fact]
public void NewAccount_BalanceZero()
{
Assert.Equal(0, _account.Balance);
}
[Fact]
public void NewAccount_CorrectAccountNumber()
{
Assert.Equal(AccountNumber, _account.AccountNumber);
}
[Fact]
public void NewAccount_EmptyString_Fails()
{
Assert.Throws<ArgumentException>(
() => new BankAccount(string.Empty));
}
// TearDown
public void Dispose()
{
}
}
}
I have a generic delegate like this:
public delegate T SomeHandler<T>(T input);
I have a generic class that take the delegate as a parameter to its constructor like this:
public class SomeClass<T>
{
private SomeHandler<T> m_handler;
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
Most of the time I would instantiate the class with a default handler unless some special case is needed. So I have some default handlers for the types I use:
public static class DefaultHandlers
{
public static string DefaultStringHandler(string input)
{
return input;
}
}
In some cases, the type is instantiated with a special handler that is specific to its implementation:
public class Example
{
private SomeClass<string> m_typicalCase;
private SomeClass<string> m_specialCase;
public Example()
{
m_typicalCase = new SomeClass<string>(DefaultHandlers.DefaultStringHandler);
m_specialCase = new SomeClass<string>(SpecialHandler);
}
private string SpecialHandler(string input)
{
string result;
// Do something special
return result;
}
}
I want to create a default constructor for SomeClass that always instantiates the class with the same default handler for that type, but since the type is not know at compile time, I can't return the delegate that is the right type.
public class SomeClass<T>
{
...
public SomeClass()
{
m_handler = DefaultHandlers.GetDefaultHandler<T>();
}
...
}
Like this
public static class DefaultHandlers
{
public static SomeHandler<T> GetDefaultHandler<T>()
{
if (typeof(T) == typeof(string))
{
return DefaultStringHandler;
}
}
}
This does not work becuase DefaultStringHandler returns a string and the method expects T.
The only way that I have found to do this is the make a type-specific subclass of SomeClass that overloads the default constructor:
public class SomeStringClass : SomeClass<string>
{
public SomeStringClass()
: base(DefaultHandlers.DefaultStringHandler)
{
}
public SomeStringClass(SomeHandler<string> handler)
: base(handler)
{
}
}
It would be fun if generic types could have type-specific overloaded constructors that are used when instantiating the class of a specific type:
public class Foo<T>
{
public Foo<string>(string input)
{
}
public Foo<int>(int input)
{
}
public Foo(T input)
{
}
}
There must be a more elegant way to do with with a design pattern, Strategy maybe?
You could utilize dynamic to get something like SomeClass<string>():
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Zoltan
{
public class SomeClass<T>
{
private static readonly Func<T,T> FALL_BACK_HANDLER = a => a; //or what have you
private readonly Func<T,T> m_handler;
public SomeClass(Func<T,T> handler)
{
m_handler = handler;
}
public SomeClass()
{
m_handler = DefaultHandler.For<T>() ?? FALL_BACK_HANDLER;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
Console.WriteLine(result);
}
}
public static class DefaultHandler
{
public static Func<T,T> For<T>()
{
return TypeAware<T>.Default;
}
private static class TypeAware<T>
{
private static readonly Func<T,T> DEFAULT;
static TypeAware()
{
var type = typeof(T);
if (type == typeof(string))
{
DEFAULT = a => DefaultHandler.StringHandler((dynamic) a);
}
else if (type == typeof(int))
{
DEFAULT = a => DefaultHandler.IntHandler((dynamic) a);
}
else
{
DEFAULT = null;
}
}
public static Func<T,T> Default { get { return DEFAULT; } }
}
public static string StringHandler(string a)
{
return a + " The default handler does some stuff!";
}
public static int IntHandler(int a)
{
return a + 2;
}
}
}
You would then consume SomeClass as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Zoltan
{
public class Program
{
public static void Main(string[] args)
{
var someStringObj = new SomeClass<string>();
someStringObj.DoSomeStuff("Hello World.");//prints "Hello World. The default handler does some stuff!"
var someIntObj = new SomeClass<int>();
someIntObj.DoSomeStuff(1);//prints 3
var someCustomDoubleObj = new SomeClass<double>(d => d - 2);
someCustomDoubleObj.DoSomeStuff(3);//prints 1
Console.Read();
}
}
}
Building on Jon Skeet and Alexei Levenkovs comments. From what I understand, something like this might be what you're after?
public delegate T SomeHandler<T>(T input);
public class SomeClass<T>
{
private SomeHandler<T> m_handler;
public SomeClass()
{
m_handler = (T input) => input;
}
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
Another way would be to move the string-specific behaviour into a separate class and simply make an instance of that class if you want specific behaviour tied to a specific type
public delegate T SomeHandler<T>(T input);
public class SomeClass<T>
{
protected SomeHandler<T> m_handler;
protected SomeClass()
{
}
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
public class SomeStringClass : SomeClass<string>
{
public SomeStringClass()
{
m_handler = DefaultStringHandler;
}
private string DefaultStringHandler(string input)
{
// Do default string stuff here...
return input;
}
public SomeStringClass(SomeHandler<string> handler):base(handler)
{
}
}
I have an <asp:Label> I wish to populate depending on the Generic object that I pass to it.
At the moment I have the following code:-
private void PopulateEnglishQuestion(int questionId)
{
ReportQuestion reportQuestion = questionsBll.GetReportQuestions().Where(x=> x.ReportQuestionId == questionId).FirstOrDefault();
PopulateLabels(reportQuestion);
}
private void PopulateTranslatedQuesiton(int questionId)
{
ReportQuestionTranslation reportQuestionTranslation = questionsBll.GetReportQuestionsTranslation().Where(x => x.QuestionId == questionId).FirstOrDefault();
PopulateLabels(reportQuestionTranslation);
}
private void PopulateLabels<T>(T item)
{
lblQuestionTitle.Text = typeof (T) == typeof (ReportQuestion)
? ((ReportQuestion) (item)).ReportQuestionTitle
: ((ReportQuestionTranslation) (item)).ReportQuestionTitleTrans;
}
How can I get the method PopulateLabels to work properly?
You should use an interface both ReportQuestion and ReportQuestionTranslation implement:
interface IQuestion
{
string TitleText;
}
Then, use the following code:
public void PopulateLabels(IQuestion item)
{
lblQuestionTitle.Text = item.TitleText;
}
Use an interface.
public interface IQuestion
{
string Title { get; }
}
public class ReportQuestion : IQuestion
{
public string Title { get { return ReportQuestionTitle; } }
}
public class ReportQuestionTranslation: IQuestion
{
public string Title { get { return ReportQuestionTitleTrans; } }
}
private void PopulateLabels(IQuestion item)
{
lblQuestionTitle.Text = item.Title;
}
Or use method overloading:
public void PopulateTitle(ReportQuestion question)
{
lblQuestionTitle.Text = question.ReportQuestionTitle;
}
public void PopulateTitle(ReportQuestionTranslation question)
{
lblQuestionTitle.Text = question.ReportQuestionTitleTrans;
}
Unrecommended:
public class QuestionTitleFormatter
{
public string GetTitle(object question)
{
if(question is ReportQuestion)
return ((ReportQuestion)question).ReportQuestionTitle;
if(question is ReportQuestionTranslation)
return ((ReportQuestionTranslation)question).ReportQuestionTitleTrans;
throw new NotImplementedException(string.Format("{0} is not supported", questionType.Name);
}
}
public void PopulateTitle(object question)
{
var formatter = new QuestionTitleFormatter();
lblQuestionTitle.Text = formatter.GetTitle(question);
}
The ToString() approach would be something like this:
class ReportQuestion {
public override string ToString() { return ReportQuestionTitle; }
...
}
class ReportQuestionTranslation{
public override string ToString() { return ReportQuestionTitleTrans; }
...
}
assuming that I answered my own question correctly in the comment above asking where the string will come from.
You could just override ToString() on those objects and not worry about any transformations or types in PopulateLabel.
This is how I used to make method calls:
SvcHelper.Using<SomeWebServiceClient>(proxy =>
{
proxy.SomeMethod();
}
public class SvcHelper
{
public static void Using<TClient>(Action<TClient> action) where TClient : ICommunicationObject, IDisposable, new()
{
}
}
This is how I make method calls:
ChannelFactory<ISomethingWebService> cnFactory = new ChannelFactory<ISomethingWebService>("SomethingWebService");
ISomethingWebService client = cnFactory.CreateChannel();
using (new OperationContextScope((IContextChannel)client))
{
client.SomeMethod();
}
My question is: Instead of replacing every instance of my original method call approach; Is there a way to modify my SvcHelper and do the creation of the channel in the SvcHelper constructor and then simply pass the interface like the following:
SvcHelper.Using<ISomethingWebService>(client =>
{
client.SomeMethod();
}
Hope this makes sense and thanks in advance.
First, you don't want to create a new ChannelFactory<T> every call to the Using helper method. They are the most costly thing to construct in the WCF universe. So, at bare minimum, you will want to use a caching approach there.
Second, you don't want to tie yourself to "client" types at all anymore. Just work straight with the service contract interfaces.
Starting from what you've got, here's where I'd go based on how I've done this in the past:
public class SvcHelper
{
private static ConcurrentDictionary<ChannelFactoryCacheKey, ChannelFactory> ChannelFactories = new ConcurrentDictionary<ChannelFactoryCacheKey, ChannelFactory>();
public static void Using<TServiceContract>(Action<TServiceContract> action) where TServiceContract : class
{
SvcHelper.Using<TServiceContract>(action, "*");
}
public static void Using<TServiceContract>(Action<TServiceContract> action, string endpointConfigurationName) where TServiceContract : class
{
ChannelFactoryCacheKey cacheKey = new ChannelFactoryCacheKey(typeof(TServiceContract), endpointConfigurationName);
ChannelFactory<TServiceContract> channelFactory = (ChannelFactory<TServiceContract>)SvcHelper.ChannelFactories.GetOrAdd(
cacheKey,
missingCacheKey => new ChannelFactory<TServiceContract>(missingCacheKey.EndpointConfigurationName));
TServiceContract typedChannel = channelFactory.CreateChannel();
IClientChannel clientChannel = (IClientChannel)typedChannel;
try
{
using(new OperationContextScope((IContextChannel)typedChannel))
{
action(typedChannel);
}
}
finally
{
try
{
clientChannel.Close();
}
catch
{
clientChannel.Abort();
}
}
}
private sealed class ChannelFactoryCacheKey : IEquatable<ChannelFactoryCacheKey>
{
public ChannelFactoryCacheKey(Type channelType, string endpointConfigurationName)
{
this.channelType = channelType;
this.endpointConfigurationName = endpointConfigurationName;
}
private Type channelType;
public Type ChannelType
{
get
{
return this.channelType;
}
}
private string endpointConfigurationName;
public string EndpointConfigurationName
{
get
{
return this.endpointConfigurationName;
}
}
public bool Equals(ChannelFactoryCacheKey compareTo)
{
return object.ReferenceEquals(this, compareTo)
||
(compareTo != null
&&
this.channelType == compareTo.channelType
&&
this.endpointConfigurationName == compareTo.endpointConfigurationName);
}
public override bool Equals(object compareTo)
{
return this.Equals(compareTo as ChannelFactoryCacheKey);
}
public override int GetHashCode()
{
return this.channelType.GetHashCode() ^ this.endpointConfigurationName.GetHashCode();
}
}
}
This should work:
public class SvcHelper
{
public static void Using<TClient>(Action<TClient> action) where TClient : ICommunicationObject, IDisposable
{
ChannelFactory<TClient> cnFactory = new ChannelFactory<TClient>("SomethingWebService");
TClient client = cnFactory.CreateChannel();
using (new OperationContextScope((IContextChannel)client))
{
action(client);
}
}
}