I want to store some generic functions for later execution. The problem arises about the arguments of functions. For different types I want to create and store same generic function delegate, but I cannot do it. Below is my version of class to get functions;
public delegate void CGTaskHandler1<T>(T value) where T : IControllerBase;
public class CGTask
{
private CGTaskHandler1<IControllerBase> Aksiyon;
private IControllerBase param;
public void RegisterCGTask(CGTaskHandler1<IControllerBase> aFunc, IControllerBase aParam)
{
Aksiyon = aFunc;
param = aParam;
}
public void ExecuteCGTask()
{
try
{
Aksiyon(param);
}
catch (Exception ex)
{
Logger.SetLog("action execution failed ", LogType.error, ex.Message)
}
}
}
by this class I used an interface to collect every different type of argument under same name, however compiler wants exact same type and interface type seems not helping.
private void LoadScene(cScene ascn)
{
ascn.LoadScene();
}
public CGTask GetTask(String btnName)
{
CGTask back = new CGTask();
CGTaskHandler1<IControllerBase> alomelo = LoadScene; // type mismatch
back.RegisterCGTask(alomelo, thisScene);
//CGTask2<cScene> back = new CGTask2<cScene>();
//CGTaskHandler1<cScene> alomelo = LoadScene;
//back.RegisterCGTask(alomelo, thisScene);
return back;
}
so I changed my cgtask class to a generic class, so, argument type would be definite since when class is instantiated.
public class CGTask2<T>
{
private CGTaskHandler1<T> Aksiyon;
private T param;
public void RegisterCGTask(CGTaskHandler1<T> aFunc, T aParam)
{
Aksiyon = aFunc;
param = aParam;
}
public void ExecuteCGTask()
{
try
{
Aksiyon(param);
}
catch (Exception ex)
{
Logger.SetLog("action execution failed ", LogType.error, ex.Message);
}
}
}
however same problem I confront when I want to collect them in a list.
List<CGTask2<IControllerBase>> gorevler = new List<CGTask2<IControllerBase>>();
gorevler.Add(new CGTask2<cScene>()); // type mismatch
I need a way to keep functions like objects. Every time I make use of a generic function delegate I need to specify the type, and types of generic functions are not convertible. Is there a way to do this, keeping references to functions and collecting these references as objects?
public interface IControllerBase
{
void GetTalker();
void InitiliazeTalker();
}
public class cControllerBase : IControllerBase
{
public cControllerBase Parent=null;
protected Talker tk;
protected void GetTalker()
{
tk = Talker.Instance; // not initialized yet
}
protected void InitiliazeTalker()
{
tk.InitializeReTalk();
}
}
public class cScene : cControllerBase, IControllerBase
{
public String ID;
public String ScenePath;
public String SceneName;
public int Slot;
public String DBParent;
public List<cAnimation> Animations;
public List<cExport> Exports;
public Boolean IsActive;
public cScene()
{
GetTalker();
Animations = new List<cAnimation>();
Exports = new List<cExport>();
// ID = Guid.NewGuid().ToString();
IsActive = false;
}
public Boolean ParseXml(String pXmlPath)
{
if (String.IsNullOrEmpty(pXmlPath)) return false;
XmlDocument xdoc = new XmlDocument();
XmlNodeList anims = null;
XmlNodeList exps = null;
try
{
xdoc.Load(pXmlPath);
anims = xdoc.SelectNodes("//scene_description/animations/animation");
exps = xdoc.SelectNodes("//scene_description/exports/export");
}
catch (Exception ex)
{
Logger.SetLog("xml parse error", LogType.error, ex.Message);
return false;
}
cAnimation tempanim;
cExport tempexport;
foreach (XmlNode x in anims)
{
tempanim = new cAnimation();
foreach (XmlAttribute y in x.Attributes)
{
switch (y.Name)
{
case "name":
{
tempanim.AnimationName = y.Value;
break;
}
case "duration":
{
tempanim.AnimationDuration = Globals.GetIntValue(y.Value);
break;
}
case "end_animation_time":
{
tempanim.AnimationEndTime = Globals.GetIntValue(y.Value);
break;
}
case "start_animation_time":
{
tempanim.AnimationStartTime = Globals.GetIntValue(y.Value);
break;
}
}
}
tempanim.Parent = this;
Animations.Add(tempanim);
}
foreach (XmlNode x in exps)
{
tempexport = new cExport();
foreach (XmlAttribute y in x.Attributes)
{
switch (y.Name)
{
case "name":
{
tempexport.ExportName = y.Value;
break;
}
case "type":
{
switch (y.Value)
{
case "String":
{
tempexport.ExportType = ExportDataType.tString;
break;
}
case "File":
{
tempexport.ExportType = ExportDataType.tFile;
break;
}
case "Float":
{
tempexport.ExportType = ExportDataType.tFloat;
break;
}
case "Int":
{
tempexport.ExportType = ExportDataType.tInt;
break;
}
case "Bool":
{
tempexport.ExportType = ExportDataType.tBool;
break;
}
}
break;
}
case "value":
{
tempexport.ExportValue = y.Value;
break;
}
}
}
tempexport.Parent = this;
Exports.Add(tempexport);
}
return true;
}
public void ActivateScene()
{
tk.ActivateScene(Slot, SceneName);
IsActive = true;
}
public void DeactivateScene()
{
// to do
// tk'dan aktif scene listesi yapıp kontrol edebiliyor musun?
tk.DeactivateScene(Slot);
IsActive = false;
}
public Boolean IsSceneLoaded()
{
Boolean back = false;
back = tk.IsSceneLoaded(SceneName);
return back;
}
public void LoadScene()
{
tk.LoadScene(SceneName);
}
public void UnloadScene()
{
tk.UnloadScene(SceneName);
}
public void SetSceneName(String strxmlPath)
{
ScenePath = strxmlPath;
SceneName = strxmlPath.Substring(0, strxmlPath.LastIndexOf('\\'));
SceneName = SceneName.Replace('\\', '/');
SceneName = SceneName.Substring(SceneName.IndexOf("Projects") + 9);
}
}
Well a CGTask2<cScene> is a completely different type to CGTask2<IControllerBase>, you can't equate the two. You would have to have a list of, for example, ITask and make CGTask2 implement that. For example:
public interface ITask {}
public class CGTask2<T> : ITask
{
//snip
}
And now you can do this:
List<ITask> gorevler = new List<ITask>();
gorevler.Add(new CGTask2<cScene>());
Related
I am trying to use haptic feedback in a Xamarin.Forms application to inform the user of selection changes. I found references to iOS and made a dependency service for iOS; however, it always crashes without any C# error. I've tried invoking it on the main thread and the thread I'm using. It even crashes in a try/catch block. Here is my code:
using System;
namespace App.Services
{
public enum HapticFeedbackType
{
ImpactHeavy, // Heavy impact
ImpactMedium, // Medium impact
ImpactLight, // Light impact
Selection, // To tick while scrolling through a scrollview or carousel
NotificationError, // When an in-app error notification occurs
NotificationWarning, // When an in-app warning notification occurs
NotificationSuccess // When an in-app success notification occurs
}
public interface IHapticFeedback
{
void PrepareHapticFeedback(HapticFeedbackType type);
void ExecuteHapticFeedback(HapticFeedbackType type);
}
}
using System;
using UIKit;
using Xamarin.Forms;
using App.Services;
[assembly: Dependency(typeof(App.iOS.Services.HapticFeedbackService))]
namespace App.iOS.Services
{
public class HapticFeedbackService : IHapticFeedback
{
HapticFeedbackHelper helper;
public HapticFeedbackService()
{
helper = new HapticFeedbackHelper();
}
public void PrepareHapticFeedback(HapticFeedbackType type)
{
helper.PrepareHapticFeedback(type);
}
public void ExecuteHapticFeedback(HapticFeedbackType type)
{
helper.ExecuteHapticFeedback(type);
}
}
//https://blog.francois.raminosona.com/add-vibrations-in-a-xamarin-ios-app/
public class HapticFeedbackHelper: IDisposable
{
private UIImpactFeedbackGenerator _impactHeavyFeedbackGenerator;
private UIImpactFeedbackGenerator _impactMediumFeedbackGenerator;
private UIImpactFeedbackGenerator _impactLightFeedbackGenerator;
private UISelectionFeedbackGenerator _selectionFeedbackGenerator;
private UINotificationFeedbackGenerator _notificationFeedbackGenerator;
public HapticFeedbackHelper()
{
_impactHeavyFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Heavy);
_impactMediumFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Medium);
_impactLightFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Light);
_selectionFeedbackGenerator = new UISelectionFeedbackGenerator();
_notificationFeedbackGenerator = new UINotificationFeedbackGenerator();
}
public void PrepareHapticFeedback(HapticFeedbackType type)
{
switch (type)
{
case HapticFeedbackType.ImpactHeavy:
_impactHeavyFeedbackGenerator.Prepare();
break;
case HapticFeedbackType.ImpactMedium:
_impactMediumFeedbackGenerator.Prepare();
break;
case HapticFeedbackType.ImpactLight:
_impactLightFeedbackGenerator.Prepare();
break;
case HapticFeedbackType.Selection:
_selectionFeedbackGenerator.Prepare();
break;
case HapticFeedbackType.NotificationError:
case HapticFeedbackType.NotificationWarning:
case HapticFeedbackType.NotificationSuccess:
_notificationFeedbackGenerator.Prepare();
break;
}
}
public void ExecuteHapticFeedback(HapticFeedbackType type)
{
switch (type)
{
case HapticFeedbackType.ImpactHeavy:
_impactHeavyFeedbackGenerator.ImpactOccurred();
break;
case HapticFeedbackType.ImpactMedium:
_impactMediumFeedbackGenerator.ImpactOccurred();
break;
case HapticFeedbackType.ImpactLight:
_impactLightFeedbackGenerator.ImpactOccurred();
break;
case HapticFeedbackType.Selection:
_selectionFeedbackGenerator.SelectionChanged();
break;
case HapticFeedbackType.NotificationError:
_notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Error);
break;
case HapticFeedbackType.NotificationWarning:
_notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Warning);
break;
case HapticFeedbackType.NotificationSuccess:
_notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Success);
break;
}
}
#region IDisposable
public void Dispose()
{
_impactHeavyFeedbackGenerator = null;
_impactMediumFeedbackGenerator = null;
_impactLightFeedbackGenerator = null;
_selectionFeedbackGenerator = null;
_notificationFeedbackGenerator = null;
}
#endregion
}
}
async void LikeDown(object sender, MR.Gestures.DownUpEventArgs e)
{
LoggingController.Info("LikeDown event started...");
if (cancelReactionShowToken?.Token != null && cancelReactionShowToken.Token.CanBeCanceled)
cancelReactionShowToken.Cancel();
cancelReactionShowToken = new CancellationTokenSource();
Task task = new Task(async delegate {
await Task.Delay(800);
if (cancelReactionShowToken.Token.IsCancellationRequested)
{
cancelReactionShowToken = null;
return;
}
MainThread.BeginInvokeOnMainThread(() =>
{
reactionPopup = new SfPopupLayout();
reactionPopup.PopupView.ShowHeader = false;
reactionPopup.PopupView.ShowFooter = false;
reactionPopup.PopupView.AutoSizeMode = AutoSizeMode.Both;
reactionPopup.PopupView.ContentTemplate = new DataTemplate(() =>
{
ReactionsView view = new ReactionsView();
this.Emojis = view.Emojis;
this.ReactionTypes = view.ReactionTypes;
return view;
});
reactionPopup.ShowRelativeToView(actionsRow, RelativePosition.AlignBottom, 0, 0);
try
{
hapticFeedback.ExecuteHapticFeedback(Services.HapticFeedbackType.Selection);
} catch (Exception ex) { Console.WriteLine(ex.Message); }
//needs to be canceled so other guestures know
cancelReactionShowToken.Cancel();
}, cancelReactionShowToken.Token);
task.Start();
await task;
}
If anyone has any experience using haptic feedback in Xamarin.Forms it would help a lot.
You need to place an exception catch-point and see exactly where the crash happens. You have placed all your code and it's difficult to figure out where you messed up. It could just be in something unrelated. You should also share your application out put that will display what the exception is.
Here's an example of the Haptic implementation by ElysiumLab.com, they also have a Nuget package that possibly has it implemented for use "Naylah":
In your core/forms project
public class HapticFeedback
{
public static IHapticFeedback Instance { get; set; }
static HapticFeedback()
{
Instance = new DefaultHapticFeedback();
}
}
internal class DefaultHapticFeedback : IHapticFeedback
{
public void Run(HapticFeedbackType hapticFeedbackType)
{
//This is a default thing should not be used;
//throw new System.Exception("Not initialized in device platforms isbrubles");
}
}
public interface IHapticFeedback
{
void Run(HapticFeedbackType hapticFeedbackType);
}
public enum HapticFeedbackType
{
Softy,
Medium,
Heavy
}
iOS Implementation
public class HapticFeedbackService
{
public static void Init()
{
HapticFeedback.Instance = new iOSHapticFeedback();
}
}
public class iOSHapticFeedback : IHapticFeedback
{
public void Run(HapticFeedbackType hapticFeedbackType)
{
UIImpactFeedbackGenerator impact = null;
switch (hapticFeedbackType)
{
case HapticFeedbackType.Softy:
impact = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Light);
break;
case HapticFeedbackType.Medium:
impact = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Medium);
break;
case HapticFeedbackType.Heavy:
impact = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Heavy);
break;
}
impact.Prepare();
impact.ImpactOccurred();
}
}
Btw, you can also create an Android implementation for the Haptic Feedback like this:
public class HapticFeedbackService
{
public static void Init(Activity activity)
{
HapticFeedback.Instance = new AndroidHapticFeedback(activity);
}
}
internal class AndroidHapticFeedback : IHapticFeedback
{
private readonly Activity activity;
public AndroidHapticFeedback(Activity activity)
{
this.activity = activity;
}
public void Run(HapticFeedbackType hapticFeedbackType)
{
switch (hapticFeedbackType)
{
case HapticFeedbackType.Softy:
activity.Window.DecorView.RootView.PerformHapticFeedback(FeedbackConstants.ContextClick);
break;
case HapticFeedbackType.Medium:
activity.Window.DecorView.RootView.PerformHapticFeedback(FeedbackConstants.KeyboardPress);
break;
case HapticFeedbackType.Heavy:
activity.Window.DecorView.RootView.PerformHapticFeedback(FeedbackConstants.KeyboardPress);
break;
}
}
}
You can check out the detailed code here, but if you are just looking for an iOS implementation you can see here.
I'm developing an application for detecting motion within webcam frames.
For this, I'm using IBasicVideoEffect for extracting frames one by one from MediaCapture. I have created class CustomEffect which inherits IBasicVideoEffect. I have used OpenCV for motion detection, it is working fine. It is also giving me motion detection level. I want to raise event from CustomEffect if motion level is greater than threshold.
But for videoDefination code is:
var videoDefinition = new VideoEffectDefinition(typeof(CustomEffect).ToString());
Here for videoDefinition constructor it is asking for ClassID,
How can i get event from CustomEffect object.
I want to raise custom event from CustomEffect (eg.: MotionDetectedEvent )
Here is my CustomEffect class:
public sealed class CustomEffect : IBasicVideoEffect
{
private OpenCVHelper _helper;
private IPropertySet _configuration;
internal event EventHandler<EventArgs> MotionDetected;
public void SetProperties(IPropertySet configuration)
{
_configuration = configuration;
}
public void SetEncodingProperties(VideoEncodingProperties encodingProperties,
IDirect3DDevice device)
{
}
private bool IsToDetectMotion
{
get
{
object val;
if (_configuration != null &&
_configuration.TryGetValue("IsToDetectMotion", out val))
return (bool) val;
return false;
}
}
public void ProcessFrame(ProcessVideoFrameContext context)
{
var tempBitmap = context.OutputFrame.SoftwareBitmap;
context.InputFrame.SoftwareBitmap.CopyTo(tempBitmap);
var originalBitmap = SoftwareBitmap.Convert(tempBitmap, BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight);
var outputBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8,
originalBitmap.PixelWidth, originalBitmap.PixelHeight,
BitmapAlphaMode.Straight);
if (!IsToDetectMotion)
{
context.InputFrame.SoftwareBitmap.CopyTo(context.OutputFrame.SoftwareBitmap);
return;
}
if (_helper == null)
_helper = new OpenCVHelper();
var level = _helper.MotionDetector(tempBitmap, outputBitmap);
RaiseMotionDetectedEvent();
Debug.WriteLine(level.ToString());
outputBitmap.CopyTo(context.OutputFrame.SoftwareBitmap);
}
private void RaiseMotionDetectedEvent()
{
if (MotionDetected != null)
MotionDetected(this, new EventArgs());
}
public void Close(MediaEffectClosedReason reason)
{
}
public void DiscardQueuedFrames()
{
}
public bool IsReadOnly { get; }
public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
{
get
{
var encodingProperties = new VideoEncodingProperties();
encodingProperties.Subtype = "ARGB32";
return new List<VideoEncodingProperties> {encodingProperties};
// If the list is empty, the encoding type will be ARGB32.
// return new List<VideoEncodingProperties>();
}
}
public MediaMemoryTypes SupportedMemoryTypes { get; }
public bool TimeIndependent { get; }
}
//in Windows Runtime Component
public sealed class FrameArgs
{
public FrameArgs(int frameCount)
{
FrameCount = frameCount;
}
public int FrameCount
{ get; }
}
public sealed partial class CustomEffect
{
#region ProcessFrameCompleted
public EventHandler<Object> ProcessFrameCompleted
{
get
{
object val;
if (configuration != null && configuration.TryGetValue(nameof(ProcessFrameCompleted), out val))
{
return (EventHandler<Object>)val;
}
return null;
}
}
public void RaiseProcessFrameCompleted(FrameArgs args)
{
ProcessFrameCompleted?.Invoke(null, (Object)args);
}
#endregion
//call as necessary
//RaiseProcessFrameCompleted(new FrameArgs(frameCount));
}
//in your app
public static async Task<IMediaExtension> AddCustomEffect(MediaCapture mediaCapture, EventHandler<FrameArgs> callBack)
{
if (mediaCapture == null)
{
throw new ArgumentException("Parameter cannot be null", nameof(mediaCapture));
}
var videoEffectDefinition =
// ReSharper disable once AssignNullToNotNullAttribute
new VideoEffectDefinition(typeof(CustomEffect).FullName);
var videoEffect =
await mediaCapture.AddVideoEffectAsync(videoEffectDefinition, MediaStreamType.VideoPreview);
videoEffect.SetProperties(
new PropertySet()
{
{
"ProcessFrameCompleted",
new EventHandler<object>((sender, e) =>
{
var args = (FrameArgs)e;
int frameCount = args.FrameCount;
callBack?.Invoke(sender, args);
})
}
});
return videoEffect;
}
I am new to c# and fairly new to programming. I need help with a topic which i have been trying to figure out from the past week. I have 3 files:
Control: this is an interface and should contain the list of my
methods
ControlImpl : this the implementaion of the interfaces.
Runtime: contains which the binding code between the main method
and the interface implementaion
Test_main: from where i call the
runtime method 'call'
Problem: there can be any number of instances(for ex: c, c1, c2, etc) in Control file and each instance should be able to call SetTime() and Nop() methods.
I made a list of the methods SetTime() and Nop(). But how can i add the instance to a list so that each instance when called should call its methods?
CONTROL
namespace create_interface
{
interface Control
{
void SetTime(params object[] paramsArr);
void Nop(params object[] paramsArr);
}
public class CM
{
Control c = new ControlImpl();
public List<object> ControlMain()
{
List<object> methods = new List<object>();
methods.Add(new Action<object[]>(c.SetTime));
methods.Add(new Action<object[]>(c.Nop));
return methods;
}
}
}
ControlImpl :
namespace create_interface
{
public class ControlImpl : Control
{
void Control.SetTime(params object[] paramsArr)
{
Console.WriteLine("inside Control.SetTime {0} ", paramsArr[0]);
}
void Control.Nop(params object[] paramsArr)
{
Console.WriteLine("inside Control.Nop ");
}
}
}
Runtime:
namespace create_interface
{
public class runtime
{
public void call(params object[] methodparams)
{
if ((methodparams[0].Equals(0)) || (methodparams[0].Equals(1)))
{
//List<Control> objectlists = cmObject.ControlObjectList();
List<object> methods = cmObject.ControlMain();
//Console.WriteLine(methods.Count);
Action<object[]> method = (Action<object[]>)methods[(int)methodparams[0]]; //object[]
object[] args = new object[] { methodparams[1] };
method(args);
}
else
Console.WriteLine("wrong ID number entered");
}
Test_main:
namespace create_interface
{
class test_main
{
static void Main(string[] args)
{
long time;
CallingFunc CF = new CallingFunc();
Console.WriteLine("enter method ID");
int methodID = Convert.ToInt32(Console.ReadLine());
try
{
switch (methodID)
{
case 0:
Console.WriteLine("enter the time in long");
time = Convert.ToInt64(Console.ReadLine());
CF.call(methodID, time);
break;
case 1:
CF.call(methodID, null);
break;
default:
Console.WriteLine("you entered wrong method ID or parameters");
break;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
Please take a look at the following solution and we can use it as a base to come up with your final solution:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace StackOverflow38200633
{
class Program
{
static void Main(string[] args)
{
Collection<IControl> controls = new Collection<IControl>();
controls.Add(ControlFactory.Create());
controls.Add(ControlFactory.Create());
controls.Add(ControlFactory.Create());
ControlManager manager = new ControlManager(controls);
Console.WriteLine("Enter method ID:");
int methodID = Convert.ToInt32(Console.ReadLine());
try
{
switch(methodID)
{
case 0:
Console.WriteLine("Enter the time in long: ");
long time = Convert.ToInt64(Console.ReadLine());
manager.InvokeAllSetTime(time);
break;
case 1:
manager.InvokeAllNop();
break;
default:
Console.WriteLine("You entered wrong method ID or parameters");
break;
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public interface IControl
{
void SetTime(long time);
void Nop();
}
public class ConcreteControl : IControl
{
public void SetTime(long time)
{
Console.WriteLine("inside Control.SetTime {0} ", time);
}
public void Nop()
{
Console.WriteLine("inside Control.Nop ");
}
}
public class ControlManager
{
public void InvokeAllSetTime(long time)
{
foreach(IControl control in _controls) control.SetTime(time);
}
public void InvokeAllNop()
{
foreach(IControl control in _controls) control.Nop();
}
public ControlManager(Collection<IControl> controls)
{
_controls = controls;
}
public Collection<IControl> _controls { get; private set; }
}
public static class ControlFactory
{
public static IControl Create()
{
return new ConcreteControl();
}
}
}
I have the following class hierarchy:
EstadoBaseMO (parent)
EstadoSAMO(EstadoBaseMO child)
EstadoGesDocMO(EstadoBaseMO child)
SolicitudBasePresenter(parent)
SolicitudGesDocPresenter(SolicitudBasePresenter child)
SolicitudSAPresenter(SolicitudBasePresenter child)
EstadoBaseBO(parent)
EstadoGesDocBO(EstadoBaseBO child)
EstadoSABO(EstadoBaseBO child)
I need to implement a method called SaveNewDetailStates, with the following implementation in SolicitudBasePresente is
public bool SaveNewDetailStates(List<EstadoBaseMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoGesDocBO bo = new EstadoGesDocBO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
SolicitudGesDocPresenter.SaveNewDetailStates implementation
public bool SaveNewDetailStates(List<EstadoGesDocMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoGesDocBO bo = new EstadoGesDocBO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
SolicitudSAPresenter.SaveNewDetailStates implementation
public bool SaveNewDetailStates(List<EstadoSAMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoSABO bo = new EstadoSABO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
As you can see, the code is exactly the same with two differences, in SolicitudSAPresenter I'm using EstadoSAMO and EstadoSABO classes, similar in SolicitudGesDocPresenter.
Things to know:
I don't really need an implementation of SolicitudBasePresenter.SaveNewDetailStates
I tried to convert the parent method(SolicitudBasePresenter.SaveNewDetailStates) to an abstract method, but then, the SAPresenter and GesDocPresenter can't use override because they need to implement the same signature (and it's not the same..), besides, soon after I realized I need a concrete implementation of SolicitudBasePresenter, so it shouldn't be an abstract class (similar happens with a virtual method)
Maybe the use of generics can solve that problem, but I'm still not used to them. I tried with something like SaveNewDetailStates<T,K>(List<T> estados), but then I'm lost and I don't know what else can I do.
What is the best approach for writing this code?
The only solution I have is to delete the SaveNewDetailStates from parent presenter, and write the concrete implementation in children and then everything is fine but...I don't think that's even a solution for a good developer..
You need to use Generics. Define the class EstadoBaseMO<T> and then use the type T in your save method.
public bool SaveNewDetailStates(List<T> estados)
Your child classes can then (for example) extend EstadoBaseMO<SolicitudBasePresenter>.
There are lots of generics tutorials online, have a look at some of them.
https://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx
you can use Generics but you still need to use Interfaces to implement what you need, but you can do it only with Interfeces similar to this, I made separate IEstadoState and IEstadoMO to make it more clear if you don't need additional fields in your logic you can make one interface instead of these two
public interface IEstadoState
{
int Id { get; set; }
}
public interface IEstadoMO
{
int Id { get; set; }
}
public interface IEstadoBO
{
IEstadoState Insert(IEstadoMO estadoMO);
}
public class SolicitudBasePresenter
{
public virtual bool SaveNewDetailStates(List<IEstadoMO> estados, IEstadoBO estadoBO)
{
bool result = true;
if (estados.Any())
{
try
{
foreach (var estado in estados)
{
var savedState = estadoBO.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
}
public class SolicitudGesDocPresenter : SolicitudBasePresenter { }
public class SolicitudSAPresenter : SolicitudBasePresenter { }
if you prefer to use Generic or don't want to pass second parameter to method here is how it will look
public class SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new()
{
public bool SaveNewDetailStates(List<T1> estados)
{
bool result = true;
if (estados.Any())
{
try
{
foreach (var estado in estados)
{
var estadoBO = new T2();
var savedState = estadoBO.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
}
public class EstadoState : IEstadoState
{
public int Id {get; set;}
}
public class EstadoBaseMO : IEstadoMO
{
public int Id { get; set; }
}
public class EstadoBaseBO : IEstadoBO
{
public IEstadoState Insert(IEstadoMO estado) { return new EstadoState(); }
}
public class EstadoSAMO : EstadoBaseMO { }
public class EstadoGesDocMO : EstadoBaseMO { }
public class EstadoGesDocBO : EstadoBaseBO { }
public class EstadoSABO : EstadoBaseBO { }
public class SolicitudGesDocPresenter : SolicitudBasePresenter<EstadoGesDocMO, EstadoGesDocBO> { }
public class SolicitudSAPresenter : SolicitudBasePresenter<EstadoSAMO, EstadoSABO> { }
your method call will be
var docPresenter = new SolicitudGesDocPresenter();
docPresenter.SaveNewDetailStates(new List<EstadoGesDocMO>());
also you can declare children like this
public class SolicitudGesDocPresenter<T1, T2> : SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new() { }
public class SolicitudSAPresenter<T1, T2> : SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new() { }
you'll call it in this way
var docPresenter = new SolicitudGesDocPresenter<EstadoGesDocMO, EstadoGesDocBO>();
docPresenter.SaveNewDetailStates(new List<EstadoGesDocMO>());
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.